<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="format-detection" content="telephone=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="icon" href="/blog/blog/images/icons/favicon-16x16.png?v=2.6.2" type="image/png" sizes="16x16"><link rel="icon" href="/blog/blog/images/icons/favicon-32x32.png?v=2.6.2" type="image/png" sizes="32x32"><meta property="og:type" content="website">
<meta property="og:title" content="斯人若彩虹 遇上方知有">
<meta property="og:url" content="https://bruce-jj.gitee.io/blog/index.html">
<meta property="og:site_name" content="斯人若彩虹 遇上方知有">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="何水浪">
<meta name="twitter:card" content="summary"><title>斯人若彩虹 遇上方知有</title><link ref="canonical" href="https://bruce-jj.gitee.io/blog/index.html"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/css/all.min.css" type="text/css"><link rel="stylesheet" href="/blog/css/index.css?v=2.6.2"><script>var Stun = window.Stun || {};
var CONFIG = {
  root: '/blog/',
  algolia: undefined,
  assistSearch: undefined,
  fontIcon: {"prompt":{"success":"fas fa-check-circle","info":"fas fa-arrow-circle-right","warning":"fas fa-exclamation-circle","error":"fas fa-times-circle"},"copyBtn":"fas fa-copy"},
  sidebar: {"offsetTop":"20px","tocMaxDepth":6},
  header: {"enable":true,"showOnPost":true,"scrollDownIcon":false},
  postWidget: {"endText":true},
  nightMode: {"enable":true},
  back2top: {"enable":true},
  codeblock: {"style":"default","highlight":"light","wordWrap":false},
  reward: false,
  fancybox: false,
  zoomImage: {"gapAside":"20px"},
  galleryWaterfall: undefined,
  lazyload: false,
  pjax: undefined,
  externalLink: {"icon":{"enable":true,"name":"fas fa-external-link-alt"}},
  shortcuts: undefined,
  prompt: {"copyButton":"复制","copySuccess":"复制成功","copyError":"复制失败"},
  sourcePath: {"js":"js","css":"css","images":"images"},
};

window.CONFIG = CONFIG;</script><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/blog/atom.xml" title="斯人若彩虹 遇上方知有" type="application/atom+xml">
</head><body><div class="container" id="container"><header class="header" id="header"><div class="header-inner"><nav class="header-nav header-nav--fixed"><div class="header-nav-inner"><div class="header-nav-menubtn"><i class="fas fa-bars"></i></div><div class="header-nav-menu"><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/blog/"><span class="header-nav-menu-item__icon"><i class="fas fa-home"></i></span><span class="header-nav-menu-item__text">首页</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/blog/archives/"><span class="header-nav-menu-item__icon"><i class="fas fa-folder-open"></i></span><span class="header-nav-menu-item__text">归档</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/blog/categories/"><span class="header-nav-menu-item__icon"><i class="fas fa-layer-group"></i></span><span class="header-nav-menu-item__text">分类</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/blog/tags/"><span class="header-nav-menu-item__icon"><i class="fas fa-tags"></i></span><span class="header-nav-menu-item__text">标签</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/blog/friends/"><span class="header-nav-menu-item__icon"><i class="fas fa-link"></i></span><span class="header-nav-menu-item__text">友链</span></a></div></div><div class="header-nav-search"><span class="header-nav-search__icon"><i class="fas fa-search"></i></span><span class="header-nav-search__text">搜索</span></div><div class="header-nav-mode"><div class="mode"><div class="mode-track"><span class="mode-track-moon"></span><span class="mode-track-sun"></span></div><div class="mode-thumb"></div></div></div></div></nav><div class="header-banner"><div class="header-banner-info"><div class="header-banner-info__title">斯人若彩虹 遇上方知有</div><div class="header-banner-info__subtitle"></div></div></div></div></header><main class="main" id="main"><div class="main-inner"><div class="content-wrap" id="content-wrap"><div class="content content-home" id="content"><section class="postlist"><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/25/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%AD%A6%E4%B9%A0-%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F/">设计模式学习_工厂方法模式</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-25</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-25</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">613</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">4分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="工厂方法设计模式-Factory-Pattern"   >
          <a href="#工厂方法设计模式-Factory-Pattern" class="heading-link"><i class="fas fa-link"></i></a><a href="#工厂方法设计模式-Factory-Pattern" class="headerlink" title="工厂方法设计模式 Factory Pattern"></a>工厂方法设计模式 Factory Pattern</h1>
      
        <h2 id="定义以及抽象层面"   >
          <a href="#定义以及抽象层面" class="heading-link"><i class="fas fa-link"></i></a><a href="#定义以及抽象层面" class="headerlink" title="定义以及抽象层面"></a>定义以及抽象层面</h2>
      <ul>
<li><strong>工厂方法定义了一种更好地创造对象的方式。但是它让工厂子类来决定怎么创造以及创造哪一个对象。也就是说，工厂模式将创造对象的过程延迟给子类来进行。</strong></li>
</ul>
<p><strong>它以这两种东西组成：</strong></p>
<p><strong>1. 我们想要创造的对象。</strong></p>
<p><strong>2.我们用来创造这些对象的工厂。</strong></p>
<p>抽象层面的图所示：</p>
<p><img   src="https://img-blog.csdnimg.cn/2021052520590059.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br><strong># 我们可以看到：</strong></p>
<p><strong>1. 左边代表的是各个我们需要创建的对象。</strong></p>
<p><strong>2. 右边代表的是我们用什么（工厂）来创建，当然了，根据什么规则来创建这些对象，我们也可以写在工厂中。</strong></p>

        <h2 id="具体案例层面以及代码实现"   >
          <a href="#具体案例层面以及代码实现" class="heading-link"><i class="fas fa-link"></i></a><a href="#具体案例层面以及代码实现" class="headerlink" title="具体案例层面以及代码实现"></a>具体案例层面以及代码实现</h2>
      <p><strong># 现在，我们用可以实现的代码形式来说明：</strong></p>
<p>重要的图如下：</p>
<p><img   src="https://img-blog.csdnimg.cn/20210525210510585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<ul>
<li>也就是说，业务场景如下：我们需要创造一个可以画出形状的图形：可以是画出长方形，正方形或者圆形。我们利用工厂类来有逻辑地创造这些类。</li>
</ul>
<ol>
<li><p>接口 形状 Shape.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.inter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
<li><p>具体的实现子类.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.Shape;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Circle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;画出来的是圆形图案...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.Shape;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;画出来的是长方形图案...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.Shape;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Square</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;画出来的是正方形图案...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<ol start="3">
<li><p>创造指定对象的工厂.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.factory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.impl.Circle;</span><br><span class="line"><span class="keyword">import</span> com.company.impl.Rectangle;</span><br><span class="line"><span class="keyword">import</span> com.company.impl.Square;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.Shape;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ShapeFactory</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Shape <span class="title">getShape</span><span class="params">(String specificShapeName)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//定义如何生成对象的逻辑</span></span><br><span class="line">        <span class="keyword">if</span> (specificShapeName.equals(<span class="string">&quot;Rectangle&quot;</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> Rectangle();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (specificShapeName.equals(<span class="string">&quot;Square&quot;</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> Square();</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (specificShapeName.equals(<span class="string">&quot;Circle&quot;</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> Circle();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
<li><p>测试的主函数Main.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.factory.ShapeFactory;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.Shape;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ShapeFactory shapeFactory = <span class="keyword">new</span> ShapeFactory();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//通过指定不同的名字 来创造不同的对象（依照具体的业务场景来定义不同的对象创建规则）</span></span><br><span class="line">        Shape s1 = shapeFactory.getShape(<span class="string">&quot;Circle&quot;</span>);</span><br><span class="line">        s1.draw();</span><br><span class="line"></span><br><span class="line">        Shape s2 = shapeFactory.getShape(<span class="string">&quot;Square&quot;</span>);</span><br><span class="line">        s2.draw();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>

        <h2 id="效果图"   >
          <a href="#效果图" class="heading-link"><i class="fas fa-link"></i></a><a href="#效果图" class="headerlink" title="效果图"></a>效果图</h2>
      <p><img   src="https://img-blog.csdnimg.cn/20210525211649951.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/23/Java%E6%8A%80%E5%B7%A7-%E9%85%8D%E7%BD%AE%E8%A7%86%E5%9B%BE%E8%A7%A3%E6%9E%90%E5%99%A8/">Java技巧_配置视图解析器</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-23</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-23</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">105</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">1分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="SpringBoot配置MVC视图解析"   >
          <a href="#SpringBoot配置MVC视图解析" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringBoot配置MVC视图解析" class="headerlink" title="SpringBoot配置MVC视图解析"></a>SpringBoot配置MVC视图解析</h1>
      <ul>
<li><strong>首先确保自己创建的是SpringBoot项目</strong></li>
</ul>
<p><strong>项目结构图如下：</strong><br><img   src="https://img-blog.csdnimg.cn/20210523113008103.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br>接下来正式开始配置：</p>

        <h2 id="1-在SpringBoot的配置文件中"   >
          <a href="#1-在SpringBoot的配置文件中" class="heading-link"><i class="fas fa-link"></i></a><a href="#1-在SpringBoot的配置文件中" class="headerlink" title="1. 在SpringBoot的配置文件中"></a>1. 在SpringBoot的配置文件中</h2>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">spring.mvc.view.prefix=classpath:/<span class="keyword">static</span>/</span><br><span class="line">spring.mvc.view.suffix=.html</span><br></pre></td></tr></table></div></figure>
<p><mark>（主要看图配置！）</mark></p>

        <h2 id="2-Controller层写代码跳转即可"   >
          <a href="#2-Controller层写代码跳转即可" class="heading-link"><i class="fas fa-link"></i></a><a href="#2-Controller层写代码跳转即可" class="headerlink" title="2. Controller层写代码跳转即可"></a>2. Controller层写代码跳转即可</h2>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/user&quot;)</span></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span></span>&#123;</span><br><span class="line">	<span class="meta">@GetMapping(&quot;/index&quot;)</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> String <span class="title">toIndex</span><span class="params">()</span></span>&#123;</span><br><span class="line">	    <span class="keyword">return</span> <span class="string">&quot;index&quot;</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>注意，这里不能用@RestController注解</strong></p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/22/SpringSecurity%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">Spring Security学习笔记</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-22</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-23</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">4.1k</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">32分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="安全保证框架"   >
          <a href="#安全保证框架" class="heading-link"><i class="fas fa-link"></i></a><a href="#安全保证框架" class="headerlink" title="安全保证框架"></a>安全保证框架</h1>
      <p>Shiro与Spring security</p>
<p><strong>他们之间很像，除了名字、类名不一样。</strong></p>

        <h2 id="Spring-Security"   >
          <a href="#Spring-Security" class="heading-link"><i class="fas fa-link"></i></a><a href="#Spring-Security" class="headerlink" title="Spring Security"></a>Spring Security</h2>
      <p><img   src="https://img-blog.csdnimg.cn/20210505205603112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<ol>
<li><p>可以实现定制化身份认证 Authentication</p>
</li>
<li><p>权限控制 Access of Control</p>
</li>
</ol>
<p>权限：</p>
<ul>
<li><p>功能权限</p>
</li>
<li><p>访问权限</p>
</li>
<li><p>菜单权限</p>
</li>
</ul>
<p><strong>Spring Security 用于简化过滤器&amp;拦截器</strong></p>
<p><img   src="https://img-blog.csdnimg.cn/20210505210813433.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<ul>
<li><p>WebSecurityConfigurerAdapter：自定义Security策略（适配器模式）</p>
</li>
<li><p>AuthenticationManagerBuilder：自定义认证策略（建造者模式）</p>
</li>
</ul>

        <h2 id="AOP概念"   >
          <a href="#AOP概念" class="heading-link"><i class="fas fa-link"></i></a><a href="#AOP概念" class="headerlink" title="AOP概念"></a>AOP概念</h2>
      <p>我们不用改变原来项目的业务代码，而是在项目中加入<code>config</code>。帮我们去做一些事情</p>

        <h1 id="入门案例"   >
          <a href="#入门案例" class="heading-link"><i class="fas fa-link"></i></a><a href="#入门案例" class="headerlink" title="入门案例"></a>入门案例</h1>
      <ul>
<li><p>使用工具idea，新建一个Spring initize项目（只勾选一个web即可）</p>
</li>
<li><p>使用SpringBoot 2.2.1版本来使用: pom.xml文件中修改</p>
</li>
<li><p>添加springboot-security依赖</p>
</li>
</ul>

        <h2 id="修改controller-体验security"   >
          <a href="#修改controller-体验security" class="heading-link"><i class="fas fa-link"></i></a><a href="#修改controller-体验security" class="headerlink" title="修改controller 体验security"></a>修改controller 体验security</h2>
      <p>在controller包下新增TestController.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/test&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">add</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, Spring Security!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="修改默认端口（避免占用）"   >
          <a href="#修改默认端口（避免占用）" class="heading-link"><i class="fas fa-link"></i></a><a href="#修改默认端口（避免占用）" class="headerlink" title="修改默认端口（避免占用）"></a>修改默认端口（避免占用）</h2>
      <p>在application.properties中</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">server.port = <span class="number">8181</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="启动项目并测试"   >
          <a href="#启动项目并测试" class="heading-link"><i class="fas fa-link"></i></a><a href="#启动项目并测试" class="headerlink" title="启动项目并测试"></a>启动项目并测试</h2>
      <figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">localhost:8181/test/hello</span><br></pre></td></tr></table></div></figure>

<p>系统会出现这个界面：<br><img   src="https://img-blog.csdnimg.cn/20210506150610548.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br>Spring Security会强制让我们先登录。<br><img   src="https://img-blog.csdnimg.cn/2021050615072796.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<ol>
<li><p>默认的用户名：<code>user</code></p>
</li>
<li><p>控制台（如图）会出现我们的默认密码<code>Using generated security password</code></p>
</li>
</ol>
<p><strong>在正确输入后，会出现下图效果：</strong><br><img   src="https://img-blog.csdnimg.cn/20210506150809240.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h1 id="SpringSecurity-基本原理（过滤链）"   >
          <a href="#SpringSecurity-基本原理（过滤链）" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringSecurity-基本原理（过滤链）" class="headerlink" title="SpringSecurity 基本原理（过滤链）"></a>SpringSecurity 基本原理（过滤链）</h1>
      <p>Spring Security框架本质上就是<strong>一套的过滤器链 FilterChain</strong></p>
<p>也就是说，有很多的过滤器Filter，执行到具体方法时，就会进入过滤器，只有过滤器对其进行过滤放行，才能进入到下一个过滤器。</p>

        <h2 id="常见三个过滤器"   >
          <a href="#常见三个过滤器" class="heading-link"><i class="fas fa-link"></i></a><a href="#常见三个过滤器" class="headerlink" title="常见三个过滤器"></a>常见三个过滤器</h2>
      
        <h3 id="FilterSecurityInterceptor"   >
          <a href="#FilterSecurityInterceptor" class="heading-link"><i class="fas fa-link"></i></a><a href="#FilterSecurityInterceptor" class="headerlink" title="FilterSecurityInterceptor"></a>FilterSecurityInterceptor</h3>
      <p>FilterSecurityInterceptor是一个方法级的权限过滤器，具体有doFilter方法。</p>
<p>首先看之前的过滤器是否执行，如果执行，才执行自己的过滤器。</p>

        <h3 id="ExceptionTranslationFilter"   >
          <a href="#ExceptionTranslationFilter" class="heading-link"><i class="fas fa-link"></i></a><a href="#ExceptionTranslationFilter" class="headerlink" title="ExceptionTranslationFilter"></a>ExceptionTranslationFilter</h3>
      <p>ExceptionTranslationFilter是一个处理权限过程中，出现的异常问题的过滤器。依据每个不同的异常，做不同的处理。</p>

        <h3 id="UsernamePasswordAuthenticationFilter"   >
          <a href="#UsernamePasswordAuthenticationFilter" class="heading-link"><i class="fas fa-link"></i></a><a href="#UsernamePasswordAuthenticationFilter" class="headerlink" title="UsernamePasswordAuthenticationFilter"></a>UsernamePasswordAuthenticationFilter</h3>
      <p>对<code>/login</code>且使用POST请求过来的表单做一个用户名密码校验。</p>

        <h1 id="SpringSecurity-过滤器的加载过程"   >
          <a href="#SpringSecurity-过滤器的加载过程" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringSecurity-过滤器的加载过程" class="headerlink" title="SpringSecurity 过滤器的加载过程"></a>SpringSecurity 过滤器的加载过程</h1>
      
        <h2 id="使用Spring-Security配置过滤器"   >
          <a href="#使用Spring-Security配置过滤器" class="heading-link"><i class="fas fa-link"></i></a><a href="#使用Spring-Security配置过滤器" class="headerlink" title="使用Spring Security配置过滤器"></a>使用Spring Security配置过滤器</h2>
      <p>如果使用SpringBoot项目的话，自动帮我们集成以下的这些代码。</p>
<ul>
<li>如果不用SpringBoot项目集成SpringSecurity的话，需要写一个DelegationFilterProxy过滤器。</li>
</ul>
<p>而这个DelegationFilterProxy的doFilter方法中，有一个init初始化方法，这个初始化方法中，用于获得FilterChainProxy，这个Proxy中有一个doFilterInternal方法，这个方法中有一个<code>List&lt;Filter&gt;</code>很多个过滤器，并通过迭代的方式<code>getFilters</code>获得这些所有的过滤器。</p>

        <h1 id="SpringSecurity-中重要的接口"   >
          <a href="#SpringSecurity-中重要的接口" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringSecurity-中重要的接口" class="headerlink" title="SpringSecurity 中重要的接口"></a>SpringSecurity 中重要的接口</h1>
      
        <h2 id="UserDetailsService-用户细节信息接口"   >
          <a href="#UserDetailsService-用户细节信息接口" class="heading-link"><i class="fas fa-link"></i></a><a href="#UserDetailsService-用户细节信息接口" class="headerlink" title="UserDetailsService 用户细节信息接口"></a>UserDetailsService 用户细节信息接口</h2>
      <p>在实际开发中，我们的账号和密码，并不是Spring Security所默认的user和默认生成密码。</p>
<p>而都是从数据库中查询出来的。</p>
<p>因此，这个接口很方便我们进行自定义逻辑业务开发。</p>
<p><strong>实现这个UserDetailsService接口即可，在这个实现方法中，写查数据库的方法。</strong></p>
<ol>
<li><p>创建一个类，继承UsernamePasswordAuthenticationFilter过滤器（重写三个方法）</p>
</li>
<li><p> 创建一个类，重新UserDetailsService接口，编写查询数据过程，并返回User对象（这个对象由Security提供）</p>
</li>
</ol>

        <h2 id="PasswordEncoder-密码加密接口"   >
          <a href="#PasswordEncoder-密码加密接口" class="heading-link"><i class="fas fa-link"></i></a><a href="#PasswordEncoder-密码加密接口" class="headerlink" title="PasswordEncoder 密码加密接口"></a>PasswordEncoder 密码加密接口</h2>
      <p>在上一个<strong>UserDetailsService</strong>中我们<strong>需要返回一个Spring Security框架中的User对象，在这个对象中的密码，必须是要返回加密后的密码。而不能是明文。</strong></p>

        <h1 id="Web项目中-认证-amp-授权-思路"   >
          <a href="#Web项目中-认证-amp-授权-思路" class="heading-link"><i class="fas fa-link"></i></a><a href="#Web项目中-认证-amp-授权-思路" class="headerlink" title="Web项目中 认证&amp;授权 思路"></a>Web项目中 认证&amp;授权 思路</h1>
      <p><strong>认证 Authentication</strong>： 就是用户在登录Web中，利用自己的用户名与密码，进行用户认证。</p>

        <h2 id="设置登录的用户名与密码"   >
          <a href="#设置登录的用户名与密码" class="heading-link"><i class="fas fa-link"></i></a><a href="#设置登录的用户名与密码" class="headerlink" title="设置登录的用户名与密码"></a>设置登录的用户名与密码</h2>
      <ol>
<li><p>通过 application.properties 配置文件进行配置</p>
</li>
<li><p>通过配置类</p>
</li>
<li><p>通过自定义编写实现类，实现UserDetialsService，返回这个User对象即可</p>
</li>
</ol>

        <h3 id="1-通过配置文件"   >
          <a href="#1-通过配置文件" class="heading-link"><i class="fas fa-link"></i></a><a href="#1-通过配置文件" class="headerlink" title="1. 通过配置文件"></a>1. 通过配置文件</h3>
      <p><img   src="https://img-blog.csdnimg.cn/20210506154818396.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br>配置代码如下：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">spring.security.user.name = user</span><br><span class="line">spring.security.user.password = <span class="number">123456</span></span><br></pre></td></tr></table></div></figure>



        <h2 id="2-通过自定义配置类"   >
          <a href="#2-通过自定义配置类" class="heading-link"><i class="fas fa-link"></i></a><a href="#2-通过自定义配置类" class="headerlink" title="2. 通过自定义配置类"></a>2. 通过自定义配置类</h2>
      <ol>
<li><p>添加注解@configuration</p>
</li>
<li><p>继承WebSecurityConfigurerAdapter类</p>
</li>
<li><p>重写这个类的方法（如下图）<br><img   src="https://img-blog.csdnimg.cn/20210506155540523.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
</li>
</ol>
<p><strong>在重写这个方法时，我们利用auth来配置用户信息，对于密码需要加密。</strong></p>
<p>而且，<strong>要记得加一个@bean注解用于验证PasswordEncoder映射</strong>，否则会报错。</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.password.PasswordEncoder;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecurityConfig</span>  <span class="keyword">extends</span> <span class="title">WebSecurityConfigurerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//利用这个auth来设置登录的用户信息</span></span><br><span class="line">        <span class="comment">// 密码需要加密</span></span><br><span class="line">        BCryptPasswordEncoder bCryptPasswordEncoder = <span class="keyword">new</span> BCryptPasswordEncoder();</span><br><span class="line">        String  passwordEncoded =  bCryptPasswordEncoder.encode(<span class="string">&quot;123456&quot;</span>);</span><br><span class="line">        auth.inMemoryAuthentication().withUser(<span class="string">&quot;user&quot;</span>).password(passwordEncoded).roles(<span class="string">&quot;admin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function">PasswordEncoder <span class="title">passwordEncoder</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> BCryptPasswordEncoder();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p>现在我们可以用这个<strong>用户名user 密码123456</strong>去登录了。而这个user用户，具有的角色是：<strong>admin</strong></p>

        <h2 id="3-利用UserDetailsService接口配置（开发经常用）"   >
          <a href="#3-利用UserDetailsService接口配置（开发经常用）" class="heading-link"><i class="fas fa-link"></i></a><a href="#3-利用UserDetailsService接口配置（开发经常用）" class="headerlink" title="3. 利用UserDetailsService接口配置（开发经常用）"></a>3. 利用UserDetailsService接口配置（开发经常用）</h2>
      <ol>
<li><p>创建配置类，auth使用UserDetailsService(注入一个UserDetailsService类)</p>
</li>
<li><p>编写实现类，<strong>返回User对象，这个对象由用户名、密码以及权限</strong></p>
</li>
</ol>

        <h3 id="创建配置类SecurityUserServiceConfig"   >
          <a href="#创建配置类SecurityUserServiceConfig" class="heading-link"><i class="fas fa-link"></i></a><a href="#创建配置类SecurityUserServiceConfig" class="headerlink" title="创建配置类SecurityUserServiceConfig"></a>创建配置类SecurityUserServiceConfig</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vincent.securitydemo.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.password.PasswordEncoder;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecurityUserServiceConfig</span> <span class="keyword">extends</span> <span class="title">WebSecurityConfigurerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserDetailsService userDetailsService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        auth</span><br><span class="line">                .userDetailsService(userDetailsService)</span><br><span class="line">                .passwordEncoder(passwordEncoder());</span><br><span class="line">                <span class="comment">//1. 使用UserDetailsService</span></span><br><span class="line">                <span class="comment">//2. 使用返回的PasswordEncoder @Bean加密</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function">PasswordEncoder <span class="title">passwordEncoder</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> BCryptPasswordEncoder();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="编写实现类MyUserDetailsService"   >
          <a href="#编写实现类MyUserDetailsService" class="heading-link"><i class="fas fa-link"></i></a><a href="#编写实现类MyUserDetailsService" class="headerlink" title="编写实现类MyUserDetailsService"></a>编写实现类MyUserDetailsService</h3>
      <p>编写一个实现类MyUserDetailsService去实现UserDetailsService（我们的配置类需要），重写这个loadUserByUsername方法加载用户信息。</p>
<p>注意：@Service(“userDetailsService”)</p>
<p>这个参数要与配置类中，@Autowire自动装配的名字一样。不然找不到。</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vincent.securitydemo.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.GrantedAuthority;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.authority.AuthorityUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.User;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetails;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UsernameNotFoundException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service(&quot;userDetailsService&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyUserDetailsService</span> <span class="keyword">implements</span> <span class="title">UserDetailsService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserDetails <span class="title">loadUserByUsername</span><span class="params">(String s)</span> <span class="keyword">throws</span> UsernameNotFoundException </span>&#123;</span><br><span class="line">        <span class="comment">// 手动代替查询数据库操作</span></span><br><span class="line">        List&lt;GrantedAuthority&gt; authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="string">&quot;role&quot;</span>);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> User(<span class="string">&quot;user&quot;</span>, <span class="keyword">new</span> BCryptPasswordEncoder().encode(<span class="string">&quot;123456&quot;</span>), authorityList);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<ul>
<li>注意，我们返回的User对象有三个参数：用户名，加密后的密码以及一个Collection表示具有的权限集合</li>
</ul>

        <h2 id="加入数据库操作-到MyUserDetailsService实现类中"   >
          <a href="#加入数据库操作-到MyUserDetailsService实现类中" class="heading-link"><i class="fas fa-link"></i></a><a href="#加入数据库操作-到MyUserDetailsService实现类中" class="headerlink" title="加入数据库操作 到MyUserDetailsService实现类中"></a>加入数据库操作 到MyUserDetailsService实现类中</h2>
      <p><strong>整合MybatisPlus进入到这一步，实现具体的数据库操作。</strong></p>

        <h3 id="引入相关依赖"   >
          <a href="#引入相关依赖" class="heading-link"><i class="fas fa-link"></i></a><a href="#引入相关依赖" class="headerlink" title="引入相关依赖"></a>引入相关依赖</h3>
      <ol>
<li><p>引入MybatisPlus依赖</p>
</li>
<li><p>引入MySQL依赖</p>
</li>
<li><p>引入工具类Lombok 方便实体类注解</p>
</li>
</ol>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">&lt;!--web项目依赖--&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!--security依赖--&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!--pojo注解生成get、set方法--&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;lombok&lt;/artifactId&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!--mybatis依赖--&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;com.baomidou&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;mybatis-plus-boot-starter&lt;/artifactId&gt;</span><br><span class="line">            &lt;version&gt;<span class="number">3.1</span><span class="number">.1</span>&lt;/version&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!--MySQL依赖--&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;mysql&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!--测试依赖--&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;</span><br><span class="line">            &lt;scope&gt;test&lt;/scope&gt;</span><br><span class="line">            &lt;exclusions&gt;</span><br><span class="line">                &lt;exclusion&gt;</span><br><span class="line">                    &lt;groupId&gt;org.junit.vintage&lt;/groupId&gt;</span><br><span class="line">                    &lt;artifactId&gt;junit-vintage-engine&lt;/artifactId&gt;</span><br><span class="line">                &lt;/exclusion&gt;</span><br><span class="line">            &lt;/exclusions&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br></pre></td></tr></table></div></figure>


        <h3 id="处理数据库中的User表"   >
          <a href="#处理数据库中的User表" class="heading-link"><i class="fas fa-link"></i></a><a href="#处理数据库中的User表" class="headerlink" title="处理数据库中的User表"></a>处理数据库中的User表</h3>
      <ol>
<li><p>id 自增数字主键</p>
</li>
<li><p>username varchar类型</p>
</li>
<li><p>password varchar类型</p>
</li>
</ol>

        <h3 id="处理Mapper-继承Mybatis-给我们写好的基本Mapper即可"   >
          <a href="#处理Mapper-继承Mybatis-给我们写好的基本Mapper即可" class="heading-link"><i class="fas fa-link"></i></a><a href="#处理Mapper-继承Mybatis-给我们写好的基本Mapper即可" class="headerlink" title="处理Mapper 继承Mybatis+ 给我们写好的基本Mapper即可"></a>处理Mapper 继承Mybatis+ 给我们写好的基本Mapper即可</h3>
      <ol>
<li>创建mapper包 UserMapper接口 extends BaseMapper<T> 泛型</li>
</ol>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vincent.securitydemo.mapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.mapper.BaseMapper;</span><br><span class="line"><span class="keyword">import</span> com.vincent.securitydemo.entity.User;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Repository</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">UserMapper</span> <span class="keyword">extends</span> <span class="title">BaseMapper</span>&lt;<span class="title">User</span>&gt; </span>&#123;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>


        <h3 id="重写之前MyUserDetailsService实现类中的方法-通过数据库查询"   >
          <a href="#重写之前MyUserDetailsService实现类中的方法-通过数据库查询" class="heading-link"><i class="fas fa-link"></i></a><a href="#重写之前MyUserDetailsService实现类中的方法-通过数据库查询" class="headerlink" title="重写之前MyUserDetailsService实现类中的方法 通过数据库查询"></a>重写之前MyUserDetailsService实现类中的方法 通过数据库查询</h3>
      <ol>
<li>Service实现类中 注入UserMapper对象</li>
</ol>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service(&quot;userDetailsService&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyUserDetailsService</span> <span class="keyword">implements</span> <span class="title">UserDetailsService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserMapper userMapper;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserDetails <span class="title">loadUserByUsername</span><span class="params">(String s)</span> <span class="keyword">throws</span> UsernameNotFoundException </span>&#123;</span><br><span class="line">        </span><br><span class="line">		<span class="comment">// 数据库查询语句 用于认证用户</span></span><br><span class="line">        <span class="comment">//并最终返回Security框架中的User对象</span></span><br><span class="line">		<span class="keyword">return</span> ...;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<ol start="2">
<li><p>利用Mybatis-plus中的QueryWrapper帮我们规定查询满足的条件 并通过UserMapper中的查询方法，注意判断<strong>根据用户名查询出来的User对象（我们定义的Entity）是否为空</strong></p>
</li>
<li><p>最终<strong>返回Spring Security框架自己的User对象</strong></p>
</li>
</ol>
<p><mark>注意看代码中的注释内容！！！</mark></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vincent.securitydemo.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;</span><br><span class="line"><span class="keyword">import</span> com.vincent.securitydemo.entity.User;</span><br><span class="line"><span class="keyword">import</span> com.vincent.securitydemo.mapper.UserMapper;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.GrantedAuthority;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.authority.AuthorityUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetails;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UsernameNotFoundException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.password.PasswordEncoder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service(&quot;userDetailsService&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyUserDetailsService</span> <span class="keyword">implements</span> <span class="title">UserDetailsService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserMapper userMapper;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserDetails <span class="title">loadUserByUsername</span><span class="params">(String username)</span> <span class="keyword">throws</span> UsernameNotFoundException </span>&#123;</span><br><span class="line">        <span class="comment">//数据库查询语句 用于认证用户</span></span><br><span class="line">        <span class="comment">//参数中的s 即代表用户提交表单中的用户名</span></span><br><span class="line">        <span class="comment">//现在我们要根据用户名 去查询对应的数据库中是否存在这个数据</span></span><br><span class="line"></span><br><span class="line">        QueryWrapper&lt;User&gt; wrapper = <span class="keyword">new</span> QueryWrapper&lt;&gt;(); <span class="comment">//条件构造器 通过这个构造器去做查询 类似UserExample</span></span><br><span class="line">        wrapper.eq(<span class="string">&quot;username&quot;</span>, username);</span><br><span class="line">        User user = userMapper.selectOne(wrapper);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (user == <span class="keyword">null</span>) &#123; <span class="comment">//认证失败 没有存在的用户</span></span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> UsernameNotFoundException(<span class="string">&quot;用户名不存在&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//注意我们返回的不是自己的实体类User</span></span><br><span class="line">        <span class="comment">//而是security框架给我们提供的User类</span></span><br><span class="line">        List&lt;GrantedAuthority&gt; authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="string">&quot;role&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> org.springframework.security.core.userdetails.User(user.getUsername(), <span class="keyword">new</span> BCryptPasswordEncoder().encode(user.getPassword()), authorityList);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<ol start="4">
<li><strong>这一步很关键</strong> 我们要<strong>在SpringBoot启动类中 加一个注解@MapperScan 启动Mapper 不然的话无法识别我们的Mapper</strong></li>
</ol>
<p>SecuritydemoApplication.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vincent.securitydemo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.mybatis.spring.annotation.MapperScan;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@MapperScan(&quot;com.vincent.securitydemo.mapper&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecuritydemoApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(SecuritydemoApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<ol start="5">
<li>application.properties 配置文件中 配置数据库信息</li>
</ol>
<p>对于本SpringSecurity测试的SpringBoot版本是SpringBoot 2.2.1 Release</p>
<p>因此，<strong>在引入数据库驱动时，如果使用的是MySQL8.0驱动且加入时区</strong></p>
<p>引入时，应使用：<code>com.mysql.cj.jdbc.Driver </code></p>
<figure class="highlight yml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">server.port</span> <span class="string">=</span> <span class="number">8181</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#可直接通过配置文件 来配置用户信息</span></span><br><span class="line"><span class="comment">#spring.security.user.name=user</span></span><br><span class="line"><span class="comment">#spring.security.user.password=123456</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#数据库连接</span></span><br><span class="line"><span class="string">spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver</span></span><br><span class="line"><span class="string">spring.datasource.url</span> <span class="string">=</span> <span class="string">jdbc:mysql://localhost:3306/securitydemo?characterEncoding=utf-8&amp;serverTimezone=GMT%2B8</span></span><br><span class="line"><span class="string">spring.datasource.username</span> <span class="string">=</span> <span class="string">root</span></span><br><span class="line"><span class="string">spring.datasource.password</span> <span class="string">=</span> <span class="number">123456</span></span><br><span class="line"></span><br><span class="line"><span class="string">spring.jpa.show-sql</span> <span class="string">=</span> <span class="literal">true</span> </span><br></pre></td></tr></table></div></figure>


        <h1 id="自定义登录页面-amp-设置路径不需要认证"   >
          <a href="#自定义登录页面-amp-设置路径不需要认证" class="heading-link"><i class="fas fa-link"></i></a><a href="#自定义登录页面-amp-设置路径不需要认证" class="headerlink" title="自定义登录页面&amp;设置路径不需要认证"></a>自定义登录页面&amp;设置路径不需要认证</h1>
      <p><strong>在实际的业务开发中，我们需要自己的好看的登录页面。因此接下来我们将指定登录的页面。</strong></p>
<p><strong>在实际的业务开发中，有些Controller是不需要进行验证用户权限的。我们也进行设置。</strong></p>
<p><mark>主要思路就是，在 SecurityConfig 配置类中，配置一下就可以了。</mark></p>
<p>值得注意的是，现在我们还是用到configure方法，但是里面的参数不是<code>AuthenticationManagerBuilder auth</code>，而是<code>HttpSecurity http。</code></p>
<p>我们通过<code>http.formLogin()</code> 进行一系列的设置</p>
<ol>
<li><p>设置默认登录页面的路径</p>
</li>
<li><p>设置默认登录的请求路径（SpringSecurity自动帮我们实现）</p>
</li>
<li><p>设置默认登录成功跳转的路径</p>
</li>
<li><p>设置哪些路径不需要认证，直接通过</p>
</li>
</ol>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vincent.securitydemo.config;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.crypto.password.PasswordEncoder;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecurityUserServiceConfig</span> <span class="keyword">extends</span> <span class="title">WebSecurityConfigurerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserDetailsService userDetailsService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//配置用户认证</span></span><br><span class="line">        auth</span><br><span class="line">                .userDetailsService(userDetailsService)</span><br><span class="line">                .passwordEncoder(passwordEncoder());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//完成与HTTP请求的配置设置</span></span><br><span class="line">        http.formLogin()</span><br><span class="line">                .loginPage(<span class="string">&quot;/login.html&quot;</span>) </span><br><span class="line">                 <span class="comment">//自定义自己编写的登录页面 参数是地址</span></span><br><span class="line">                .</span><br><span class="line">                loginProcessingUrl(<span class="string">&quot;/user/login&quot;</span>)  </span><br><span class="line">                <span class="comment">//定义登录访问的请求路径 但是这个具体的方法过程由SpringSecurity实现</span></span><br><span class="line">                </span><br><span class="line">                .failureUrl(<span class="string">&quot;/error.html&quot;</span>)</span><br><span class="line">                <span class="comment">//定义登录错误跳转的页面 参数是地址</span></span><br><span class="line"></span><br><span class="line">                .defaultSuccessUrl(<span class="string">&quot;index.html&quot;</span>).permitAll()   </span><br><span class="line">                <span class="comment">//定义默认登录成功后 跳转到的路径</span></span><br><span class="line">                </span><br><span class="line">                .and().authorizeRequests().antMatchers(<span class="string">&quot;/&quot;</span>, <span class="string">&quot;/test/hello&quot;</span>, <span class="string">&quot;/user/login&quot;</span>).permitAll()</span><br><span class="line">                .anyRequest().authenticated()</span><br><span class="line">                <span class="comment">//授权通过，这些路径是不需要认证，直接让它过！</span></span><br><span class="line">                </span><br><span class="line">                .and().csrf().disable(); <span class="comment">//关闭CSRF认证方式</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function">PasswordEncoder <span class="title">passwordEncoder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> BCryptPasswordEncoder();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>现在我们只需要，一个登录页面，一个处理登录成功的controller</strong></p>
<ul>
<li>注意我们这里的action值，必须<strong>跟config中配置的请求路径相同</strong>，而且<strong>name只能是用户名和密码</strong>。 </li>
</ul>
<p><em>resources/static/login.html</em></p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/user/login&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">        用户名：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span>&gt;</span> <span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        密码： <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;登录&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></div></figure>
<p><em>resources/static/error.html</em></p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>错误页面<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>抱歉，登录错误！<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p><em>resources/static/index.html</em></p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>主页面<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>登录成功，这是主界面！<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p><em>controller/TestController.java</em></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/index&quot;)</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> String <span class="title">toIndex</span><span class="params">()</span></span>&#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="string">&quot;Hello, Index!&quot;</span>;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure>


        <h1 id="基于角色或者权限的访问控制"   >
          <a href="#基于角色或者权限的访问控制" class="heading-link"><i class="fas fa-link"></i></a><a href="#基于角色或者权限的访问控制" class="headerlink" title="基于角色或者权限的访问控制"></a>基于角色或者权限的访问控制</h1>
      
        <h2 id="1-hasAuthority方法"   >
          <a href="#1-hasAuthority方法" class="heading-link"><i class="fas fa-link"></i></a><a href="#1-hasAuthority方法" class="headerlink" title="1. hasAuthority方法"></a>1. hasAuthority方法</h2>
      <p><strong>对于这个方法，如果用户具有指定的权限，则返回True，否则返回False.</strong></p>
<p><strong># 在config中声明只有哪些权限可以通过这个路径请求</strong><br><img   src="https://img-blog.csdnimg.cn/20210522204147176.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//只有具有admin权限 才能访问这个/test/index这个路径(同时在Service中加入admin）</span></span><br><span class="line">.antMatchers(<span class="string">&quot;/test/index&quot;</span>).hasAuthority(<span class="string">&quot;admin&quot;</span>)</span><br></pre></td></tr></table></div></figure>

<p><strong># Service中加入这些权限</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//在Service中加入admin权限</span></span><br><span class="line">List&lt;GrantedAuthority&gt; authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="string">&quot;admin&quot;</span>);</span><br></pre></td></tr></table></div></figure>

<p><img   src="https://img-blog.csdnimg.cn/20210522205711287.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br>当出现上述图片时，<strong>代表403权限不够！</strong></p>

        <h2 id="2-hasAnyAuthority"   >
          <a href="#2-hasAnyAuthority" class="heading-link"><i class="fas fa-link"></i></a><a href="#2-hasAnyAuthority" class="headerlink" title="2. hasAnyAuthority"></a>2. hasAnyAuthority</h2>
      <ul>
<li>当某个请求对于声明的角色中，<strong>任意一个角色都可以</strong>通过时使用。</li>
</ul>
<p><strong>比如对于学生的管理，教师Teacher与管理员Admin都可以访问这些接口路径。</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.antMatchers(<span class="string">&quot;/test/index&quot;</span>).hasAnyAuthority(<span class="string">&quot;admin,teacher&quot;</span>)</span><br></pre></td></tr></table></div></figure>

<p>则表示，当权限为teacher或者admin…等等时（用逗号隔开即可）都允许通过！</p>

        <h2 id="3-hasRole"   >
          <a href="#3-hasRole" class="heading-link"><i class="fas fa-link"></i></a><a href="#3-hasRole" class="headerlink" title="3. hasRole"></a>3. hasRole</h2>
      <ul>
<li>基本用法不变，但是源码显示：它会将我们<strong>声明的角色名xxx</strong>变成<strong>ROLE_+xxx。</strong></li>
</ul>
<p>因此，我们在Service中，声明具有的角色时，<strong>应该手动添加为ROLE_xxx。</strong></p>
<p>#配置类</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.antMatchers(<span class="string">&quot;/test/index&quot;</span>).hasRole(<span class="string">&quot;salesman&quot;</span>)</span><br></pre></td></tr></table></div></figure>

<p>#Service声明具有的权限</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List&lt;GrantedAuthority&gt; authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="string">&quot;admin,Role_salesman&quot;</span>);</span><br></pre></td></tr></table></div></figure>


        <h2 id="4-hasAnyRole"   >
          <a href="#4-hasAnyRole" class="heading-link"><i class="fas fa-link"></i></a><a href="#4-hasAnyRole" class="headerlink" title="4.  hasAnyRole"></a>4.  hasAnyRole</h2>
      <p><strong>用法与hasAnyAutority一致。</strong></p>

        <h1 id="自定义无权限403页面"   >
          <a href="#自定义无权限403页面" class="heading-link"><i class="fas fa-link"></i></a><a href="#自定义无权限403页面" class="headerlink" title="自定义无权限403页面"></a>自定义无权限403页面</h1>
      <ul>
<li>在配置类中，配置自定义403页面即可。</li>
</ul>
<p><img   src="https://img-blog.csdnimg.cn/20210522210640704.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http.exceptionHandling().accessDeniedPage(<span class="string">&quot;/unauth.html&quot;</span>);</span><br></pre></td></tr></table></div></figure>

<p>如果满足无权限条件的话，会跳转到这个页面。<br><img   src="https://img-blog.csdnimg.cn/20210522210800475.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h1 id="SpringSecurity-认证-amp-授权-常见的注解"   >
          <a href="#SpringSecurity-认证-amp-授权-常见的注解" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringSecurity-认证-amp-授权-常见的注解" class="headerlink" title="SpringSecurity 认证&amp;授权 常见的注解"></a>SpringSecurity 认证&amp;授权 常见的注解</h1>
      <ul>
<li>注解的作用，就是简化开发。</li>
</ul>

        <h2 id="Secured-“ROLE-XXX-ROLE-YYY”"   >
          <a href="#Secured-“ROLE-XXX-ROLE-YYY”" class="heading-link"><i class="fas fa-link"></i></a><a href="#Secured-“ROLE-XXX-ROLE-YYY”" class="headerlink" title="@Secured(“ROLE_XXX, ROLE_YYY”)"></a>@Secured(“ROLE_XXX, ROLE_YYY”)</h2>
      <p><strong>这个注解表示：用户具有某个角色，可以根据这个角色来访问相应的接口。</strong></p>
<p><strong>使用这个注解时，我们要打开注解功能：</strong></p>
<ol>
<li><p>添加注解到<strong>Springboot启动类</strong>或者<strong>Config配置类</strong>上：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableGlobalMethodSecurity(securedEnabled = true)</span></span><br></pre></td></tr></table></div></figure></li>
<li><p>在Controller的方法上面，使用这个注解，自动为我们判断角色权限。</p>
</li>
</ol>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/deleteUser&quot;)</span></span><br><span class="line"><span class="meta">@Secured(&quot;ROLE_admin&quot;)</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">deleteUser</span><span class="params">()</span></span>&#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="string">&quot;通过权限，这是删除页面！&quot;</span>;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>表示这个方法，必须要具有admin角色才能进入。</strong></p>

        <h2 id="PreAuthorize"   >
          <a href="#PreAuthorize" class="heading-link"><i class="fas fa-link"></i></a><a href="#PreAuthorize" class="headerlink" title="@PreAuthorize"></a>@PreAuthorize</h2>
      <ul>
<li>这个是<strong>在方法执行之前进行校验。</strong></li>
</ul>
<ol>
<li><p>在启动类相同位置，逗号，开启<strong>prePostEnabled = true</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)</span></span><br></pre></td></tr></table></div></figure></li>
<li><p>在相应方法上，加入注解**@PreAuthorize()**</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/updateUser&quot;)</span></span><br><span class="line"><span class="meta">@PreAuthorize(&quot;hasRole(&#x27;ROLE_admin&#x27;)&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">updateUser</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;通过权限，这是更改页面！&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>
<p><img   src="https://img-blog.csdnimg.cn/20210522212525782.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br>可以看到，这里可以选择之前的四种：</p>
<ol>
<li>hasRole</li>
<li>hasAnyRole</li>
<li>hasAuthority</li>
<li>hasAnyAuthority</li>
</ol>
<ul>
<li>注意涉及到Role时，手动添加<strong>ROLE_XXX</strong>即可。</li>
</ul>

        <h2 id="PostAuthorize"   >
          <a href="#PostAuthorize" class="heading-link"><i class="fas fa-link"></i></a><a href="#PostAuthorize" class="headerlink" title="@PostAuthorize"></a>@PostAuthorize</h2>
      <ul>
<li><p>这种方式用得频率比较少，<strong>代表：执行方法之后，再进行校验</strong>。<strong>一般适用于，带有返回值的校验方式！</strong></p>
</li>
<li><p><em>也就是说，方法是一定会执行的。</em>*</p>
</li>
</ul>
<p>只不过是，方法执行后，遇到了403权限错误。</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/afterMethodVerify&quot;)</span></span><br><span class="line"><span class="meta">@PostAuthorize(&quot;hasRole(&#x27;ROLE_admin&#x27;)&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">afterMethodVerify</span><span class="params">()</span></span>&#123;</span><br><span class="line">	System.out.println(<span class="string">&#x27;一定会执行的！&#x27;</span>);</span><br><span class="line">   <span class="keyword">return</span> <span class="string">&quot;通过权限，这是目标页面！&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/19/Java%E9%80%82%E5%BA%94%E5%89%8D%E7%AB%AFJSON%E5%8F%82%E6%95%B0-%E4%B8%87%E7%89%A9%E7%9A%86%E5%8F%AFMap/">Java适应前端JSON参数_万物皆可Map</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-19</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-19</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">448</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">3分</span></span></div></header><div class="post-body"><div class="post-excerpt"><p><strong>来源于之前做过的ECharts引入饼图数据：</strong></p>
<p><a href="https://bruce-jj.gitee.io/blog/2021/05/12/VUE%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95%E5%8F%8A%E7%9B%B8%E5%BA%94%E5%BA%94%E7%94%A8-4/#VUE%E4%B8%AD%E6%B7%BB%E5%8A%A0Echarts%E5%8F%AF%E8%A7%86%E5%8C%96%E5%9B%BE%E8%A1%A8">点我回顾ECharts</a></p>
<p>我们前端图表data中有两个参数：</p>
<ol>
<li><p>name 代表饼图每一部分的名称</p>
</li>
<li><p>value 代表饼图每一部分的数据量（自动根据这个数据量更改比例）</p>
</li>
</ol>
<p><strong>因此我们前端需要复杂处理：name与value</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//同步请求数据</span></span><br><span class="line">$.ajax(&#123;</span><br><span class="line">	<span class="attr">url</span>: <span class="string">&quot;$&#123;request.getContexPath()&#125;/meal/showData&quot;</span>,</span><br><span class="line">	<span class="attr">type</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">	<span class="attr">dataType</span>: <span class="string">&quot;JSON&quot;</span>,</span><br><span class="line">	<span class="attr">async</span>: <span class="literal">false</span>,</span><br><span class="line">	<span class="comment">// 回调函数</span></span><br><span class="line">	<span class="attr">success</span>: <span class="function"><span class="keyword">function</span> (<span class="params">res</span>)</span>&#123;</span><br><span class="line">		data = res <span class="comment">//这里具体看链接中 引入的饼图ECharts</span></span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="attr">error</span>: <span class="function"><span class="keyword">function</span> (<span class="params">error</span>)</span>&#123;</span><br><span class="line">		<span class="built_in">console</span>.log(error)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></div></figure>

<p><strong>data中是这样的:</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">data:[ &#123; <span class="string">&quot;name&quot;</span>: <span class="string">&quot;bookName&quot;</span>, <span class="attr">value</span>: <span class="string">&quot;20&quot;</span> &#125;]</span><br></pre></td></tr></table></div></figure>

<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">  <span class="meta">@ResponseBody</span>  <span class="meta">@RequestMapping(&quot;/showData&quot;)</span>  <span class="keyword">public</span> List&lt;Map&lt;String,Object&gt;&gt; showData(</span><br><span class="line">	Model model, </span><br><span class="line">	HttpServletRequest request)&#123;</span><br><span class="line">		      <span class="comment">//  查询所有订单信息</span>      List&lt;OrderItem&gt; list = orderItemService.list();</span><br><span class="line"></span><br><span class="line"><span class="comment">//map: productId(Integer类型) 次数(Integer类型) </span>      Map&lt;Integer,Integer&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line"><span class="comment">//遍历所有待处理的list</span>      <span class="comment">//利用map的键值唯一性统计各（具体item对象）数量</span>      list.forEach(i -&gt; &#123;</span><br><span class="line">	<span class="comment">//如果存在对应的pid 作为键 那么就累加sum</span></span><br><span class="line">	<span class="comment">//否则（第一次检索） 赋值为默认1</span>          map.merge(i.getPid(), <span class="number">1</span>, Integer::sum);      &#125;);      <span class="comment">//查询商品名字返回结果集</span></span><br><span class="line"><span class="comment">//值用Object更加的灵活</span>      List&lt;Map&lt;String,Object&gt;&gt; res = <span class="keyword">new</span> ArrayList&lt;&gt;();	      <span class="comment">//map映射转换为 集合set</span>      Set&lt;Map.Entry&lt;Integer, Integer&gt;&gt; entries = map.entrySet();</span><br><span class="line">      <span class="comment">//遍历这个集合</span>      entries.forEach(entry -&gt; &#123;          Map&lt;String,Object&gt; map1 = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">	          <span class="comment">//获取到集合中的每一个key值</span>          Integer key = entry.getKey();</span><br><span class="line">	          <span class="comment">//根据这个key值（也就是pid) 去找对应的product对象</span>          Product product = productService.get(key);</span><br><span class="line">	          <span class="comment">//将需要两个属性 put进去</span>          <span class="comment">//我们需要前端data的name:val value:value</span>          map1.put(<span class="string">&quot;name&quot;</span>, product.getName());          map1.put(<span class="string">&quot;value&quot;</span>, entry.getValue());          res.add(map1);      &#125;);      <span class="keyword">return</span>  res;  &#125;</span><br></pre></td></tr></table></div></figure>

</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/18/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%AD%A6%E4%B9%A0-%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/">设计模式学习_装饰器模式</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-18</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-19</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">1k</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">6分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="装饰器模式-Decorator-Pattern"   >
          <a href="#装饰器模式-Decorator-Pattern" class="heading-link"><i class="fas fa-link"></i></a><a href="#装饰器模式-Decorator-Pattern" class="headerlink" title="装饰器模式  Decorator Pattern"></a>装饰器模式  Decorator Pattern</h1>
      <ul>
<li>试想有一个<strong>平安夜苹果</strong>，我们用一个精美的盒子将其装入，同时我们可以按照自己的需要，在最外层继续装精美的盒子（例子不太恰当）。</li>
</ul>
<p><strong>而这就是装饰器模式，本身的工作原理。</strong></p>

        <h2 id="定义"   >
          <a href="#定义" class="heading-link"><i class="fas fa-link"></i></a><a href="#定义" class="headerlink" title="定义"></a>定义</h2>
      <p><strong>1. 装饰器模式，允许我们像现有的对象添加新的功能同时不改变其设计结构。</strong>    </p>
<p><strong>2. 是作为现有类的一个包装，即本质上，还是这个类</strong></p>
<p><strong>3. 动态扩展或者撤销类的功能</strong></p>
<p>同时，装饰器模式可以解决，一般继承Inheritance的缺陷。</p>
<p>我们知道，<strong>当一个类继承另一个类是，它必须具备这个类的所有功能（包括属性与方法）。</strong></p>
<p>这样是有缺陷的，比如：</p>
<p>我们有一个<strong>叫做Beverage 饮料的类 是一个抽象类（代表我们不能像接口一样 去实例化）</strong></p>
<p>其中，Beverage有价格属性以及得到价格的方法</p>
<p>现在Beverage有两个子类：<strong>1. 咖啡 2. 茶</strong></p>
<p><strong>现在我们按照一般的思路来添加功能，就是直接在Beverage类中添加（比如咖啡是否加牛奶）</strong></p>
<p>但是，试想一下，如果有牛奶这个属性，对于茶来说，就可能显得没必要了（抱歉如果你喜欢这么搭配，无意冒犯）</p>
<ul>
<li><strong>也就是说，部分子类有时，没必要拥有父类的所有信息。</strong></li>
</ul>
<p>所以，我们的装饰器模式就是来解决这样的问题：<strong>如何在不更改已有代码的同时，更高效地添加对象的功能。</strong></p>

        <h2 id="UML图示"   >
          <a href="#UML图示" class="heading-link"><i class="fas fa-link"></i></a><a href="#UML图示" class="headerlink" title="UML图示"></a>UML图示</h2>
      <p><img   src="https://img-blog.csdnimg.cn/20210518105159541.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<p>从这个图中，我们需要看到最重要的概念：</p>
<ol>
<li>对于装饰器来说，它<strong>即具有饮料成员变量，同时自己又是一个饮料</strong></li>
</ol>
<p><strong>很好解释：对于奶茶店里的珍珠，首先它要知道自己加到哪杯饮料上去，其次加到那杯饮料过后，它们共同组成了一杯新的饮料。</strong></p>
<p>这样，一层一层的包裹，可以动态地延展系统中对象的功能。</p>

        <h2 id="代码实现"   >
          <a href="#代码实现" class="heading-link"><i class="fas fa-link"></i></a><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h2>
      <ol>
<li><p>这里我们有Milk与Coffee两种饮料，分别卖5元与10元</p>
</li>
<li><p>这里我们有可选选项Sugar，加糖多加1元</p>
</li>
</ol>
<p>首先我们要有抽象类Beverage.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Beverage</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> <span class="title">getPrice</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p>然后我们有两个继承Beverage的Milk.java与Coffee.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Milk</span> <span class="keyword">extends</span> <span class="title">Beverage</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//假设菜单上规定 牛奶一杯5元</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getPrice</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">5</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Coffee</span> <span class="keyword">extends</span> <span class="title">Beverage</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//假设菜单上规定 咖啡一杯10元（注意，咖啡与牛奶都是基础选项）</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getPrice</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p>接下来我们要有，一个抽象类AddOnDecorator.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.decorator;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.entity.Beverage;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AddOnDecorator</span> <span class="keyword">extends</span> <span class="title">Beverage</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> <span class="title">getPrice</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p>最后我们要有自己的可选选项SugarDecorator.java去继承这个抽象类</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.decorator;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.entity.Beverage;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SugarDecorator</span> <span class="keyword">extends</span> <span class="title">AddOnDecorator</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//被包裹的内层 不管之前加了什么</span></span><br><span class="line">    <span class="comment">// （可以是咖啡来加糖 也可以是牛奶来加糖）</span></span><br><span class="line">    Beverage beverage;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SugarDecorator</span><span class="params">(Beverage beverage)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.beverage = beverage;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//这里糖是可选选项</span></span><br><span class="line">    <span class="comment">// 当你给已有的饮料加糖时 加上糖后</span></span><br><span class="line">    <span class="comment">// 仍然是饮料 还可以加其他的东西</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getPrice</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.beverage.getPrice() + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>这里的关键代码是：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Beverage beverage;</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">this</span>.beverage.getPrice() + <span class="number">1</span>;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p>就相当于<strong>给里层的饮料，加了一层价格1元</strong>，<strong>但是里层的饮料还加了什么我们不在乎。</strong></p>
<p>因为，<strong>不管加了什么可选选项，它同时就是一杯饮料。</strong></p>
<p>最后，我们用Main.java运行即可：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.decorator.SugarDecorator;</span><br><span class="line"><span class="keyword">import</span> com.company.entity.Beverage;</span><br><span class="line"><span class="keyword">import</span> com.company.entity.Coffee;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        Coffee coffee = <span class="keyword">new</span> Coffee();</span><br><span class="line">        System.out.println(<span class="string">&quot;如果只点一杯咖啡，价格是：&quot;</span> + coffee.getPrice()  + <span class="string">&quot;元&quot;</span> );</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;...&quot;</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;咖啡太苦了，准备加糖...&quot;</span>);</span><br><span class="line"></span><br><span class="line">        SugarDecorator sugarDecorator = <span class="keyword">new</span> SugarDecorator(coffee);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;加完糖后，整个饮料的价格是：&quot;</span> + sugarDecorator.getPrice());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><img   src="https://img-blog.csdnimg.cn/20210518110234967.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/17/%E6%AF%95%E4%B8%9A%E7%AD%94%E8%BE%A9-%E9%87%8D%E7%82%B9%E5%9B%BE%E8%A1%A8/">毕业答辩_重点图表</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-17</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-17</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">756</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">3分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="E-R-图"   >
          <a href="#E-R-图" class="heading-link"><i class="fas fa-link"></i></a><a href="#E-R-图" class="headerlink" title="E-R 图"></a>E-R 图</h1>
      <blockquote>
<p>E-R图也称实体-联系图(Entity Relationship Diagram)，提供了表示实体类型、属性和联系的方法，用来描述现实世界的概念模型。</p>
</blockquote>
<ol>
<li><p><strong>矩形框代表实体</strong></p>
</li>
<li><p><strong>菱形框代表联系</strong></p>
</li>
<li><p>实线上的<strong>1:1 1:m m:n</strong>分别代表<strong>一对一、一对多以及多对多关系</strong></p>
</li>
<li><p><strong>椭圆框代表实体的各个属性</strong>，如果是<strong>主键则加上下划线。</strong></p>
</li>
</ol>
<p><img   src="https://img-blog.csdnimg.cn/20210517092317501.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h1 id="时序图"   >
          <a href="#时序图" class="heading-link"><i class="fas fa-link"></i></a><a href="#时序图" class="headerlink" title="时序图"></a>时序图</h1>
      <blockquote>
<p>时序图（Sequence Diagram），又名序列图、循序图，是一种UML交互图。它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作。它可以表示用例的行为顺序，当执行一个用例行为时，其中的每条消息对应一个类操作或状态机中引起转换的触发事件。</p>
</blockquote>
<p><img   src="https://img-blog.csdnimg.cn/20210515133106187.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<p><strong>时序图由以下部分构成：</strong></p>
<ol>
<li>角色</li>
</ol>
<p><strong>角色通常是人（图中的教师）</strong>，当然也可以是系统或者子系统</p>
<ol start="2">
<li>对象</li>
</ol>
<p><strong>对象通常位于时序图的顶部</strong>，一般<strong>直接写类名即可</strong></p>
<ol start="3">
<li>生命线</li>
</ol>
<p><strong>对象下面的虚线</strong>即称为生命线，而<strong>消息在两条生命线之间进行传递</strong></p>
<ol start="4">
<li><p>控制焦点<br>控制焦点，一般指的是<strong>对象下的矩形框</strong>，即<strong>对象操作的声明周期</strong></p>
</li>
<li><p>消息<br>在两条相邻的生命线中，消息在这之间进行传递，<strong>消息传递的本质就是方法的调用</strong>。</p>
</li>
</ol>

        <h1 id="数据流图"   >
          <a href="#数据流图" class="heading-link"><i class="fas fa-link"></i></a><a href="#数据流图" class="headerlink" title="数据流图"></a>数据流图</h1>
      <blockquote>
<p>数据流图（Data Flow Diagram）：简称DFD，它从数据传递和加工角度，以图形方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程，是结构化系统分析方法的主要表达工具及用于表示软件模型的一种图示方法。</p>
</blockquote>
<p><img   src="https://img-blog.csdnimg.cn/20210517100409218.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<blockquote>
<p>值得注意的是，数据流图不是传统的流程图或框图，数据流也不是控制流。<strong>数据流图是从数据的角度来描述一个系统</strong>，而<strong>框图是从对数据进行加工的工作人员的角度来描述系统</strong>。</p>
</blockquote>
<p>也就是说，数据流图的根本，就是<strong>用不同层级来描述数据是怎样流动的，从哪里到哪里，中间经过了什么加工处理。</strong></p>
<p>数据流图，分为<strong>顶层与第一层、第二层</strong>…</p>
<p><img   src="https://img-blog.csdnimg.cn/20210517100810557.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h1 id="UML用例图"   >
          <a href="#UML用例图" class="heading-link"><i class="fas fa-link"></i></a><a href="#UML用例图" class="headerlink" title="UML用例图"></a>UML用例图</h1>
      <blockquote>
<p>用例图是用来描述系统功能的技术，表示一个系统中用例与参与者及其关系的图。</p>
</blockquote>
<p>也就是说，用例图展示的是，<strong>系统为不同参与者提供的不同（用例）的功能。</strong><br><img   src="https://img-blog.csdnimg.cn/20210515132653252.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<ol>
<li><p>参与者一般可以是系统内部的不同角色(<strong>图中的管理员</strong>）、或者也可以是系统外部的参与角色</p>
</li>
<li><p>一个用例是一个基本单元（<strong>图中的个人信息管理、教师管理</strong>等等）</p>
</li>
<li><p>用例与用例之间具备一些关系（比如<strong>图中虚线表示的的包含关系</strong>等等）</p>
</li>
</ol>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/17/%E6%AF%95%E4%B8%9A%E7%AD%94%E8%BE%A9-%E6%80%BB%E4%BD%93%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/">毕业答辩_总体注意事项</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-17</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-17</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">911</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">4分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="答辩需要注意的事情"   >
          <a href="#答辩需要注意的事情" class="heading-link"><i class="fas fa-link"></i></a><a href="#答辩需要注意的事情" class="headerlink" title="答辩需要注意的事情"></a>答辩需要注意的事情</h1>
      
        <h2 id="封面一定保持校正一致"   >
          <a href="#封面一定保持校正一致" class="heading-link"><i class="fas fa-link"></i></a><a href="#封面一定保持校正一致" class="headerlink" title="封面一定保持校正一致"></a>封面一定保持校正一致</h2>
      <ol>
<li><p><strong>大数据学院加上</strong></p>
</li>
<li><p><strong>校外指导教师不能少</strong></p>
</li>
<li><p>日期已正确 勿修改</p>
</li>
</ol>
<p><img   src="https://img-blog.csdnimg.cn/20210515133239479.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h2 id="摘要"   >
          <a href="#摘要" class="heading-link"><i class="fas fa-link"></i></a><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h2>
      <ol>
<li><p><strong>研究什么东西（涉及到论文题目的解析）</strong> </p>
</li>
<li><p>用的什么<strong>技术（SpringMVC+Spring+Mybatis 凡是论文中出现的英文名 要知道是什么）</strong> </p>
</li>
<li><p>关键词语：<strong>要体现论文的题目 言简意赅 突出业务核心 不要冗余</strong></p>
</li>
</ol>

        <h2 id="英文摘要"   >
          <a href="#英文摘要" class="heading-link"><i class="fas fa-link"></i></a><a href="#英文摘要" class="headerlink" title="英文摘要"></a>英文摘要</h2>
      <p><strong>检查单词之间是否有空格 首字母大写</strong></p>

        <h2 id="目录"   >
          <a href="#目录" class="heading-link"><i class="fas fa-link"></i></a><a href="#目录" class="headerlink" title="目录"></a>目录</h2>
      <p>一定要<strong>删掉目录中的目录。</strong></p>
<p>以及<strong>英文摘要与绪论之间</strong><br><img   src="https://img-blog.csdnimg.cn/20210515110256221.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h2 id="页眉"   >
          <a href="#页眉" class="heading-link"><i class="fas fa-link"></i></a><a href="#页眉" class="headerlink" title="页眉"></a>页眉</h2>
      <p>记得<strong>要带编号</strong></p>
<p><img src="https://img-blog.csdnimg.cn/20210515133433501.png" alt="在这里插入图片描述"></p>

        <h2 id="绪论-前言"   >
          <a href="#绪论-前言" class="heading-link"><i class="fas fa-link"></i></a><a href="#绪论-前言" class="headerlink" title="绪论 | 前言"></a>绪论 | 前言</h2>
      <p><strong>切记，不要内容太少了。要保证字数要有一页！！！</strong></p>
<p><strong>技术介绍：</strong><br>    1. Tomcat（具体是干什么的？）<br>    2. Spring…（<strong>常见的后台框架</strong>，以及简单的运作原理）<br>    3. Ajax以及前端框架Bootstrap等等（<strong>记得概念</strong>）</p>
<ul>
<li>注意，<strong>格式：如果要么是Mybatis就全文全部都是Mybatis！不要来个mybatis</strong></li>
</ul>

        <h2 id="系统分析"   >
          <a href="#系统分析" class="heading-link"><i class="fas fa-link"></i></a><a href="#系统分析" class="headerlink" title="系统分析"></a>系统分析</h2>
      <ol>
<li><p>可行性（XX可行性分析等等）</p>
</li>
<li><p> 功能分析（几个角色）</p>
</li>
<li><p>用例分析：（提供<strong>用例图（执行人以及执行功能）</strong>、增加<strong>用例说明（业务逻辑）</strong>）</p>
</li>
</ol>

        <h3 id="用例图"   >
          <a href="#用例图" class="heading-link"><i class="fas fa-link"></i></a><a href="#用例图" class="headerlink" title="用例图"></a>用例图</h3>
      <ul>
<li>要了解用例图的意义，以及其中的基本组成成分。<br><img   src="https://img-blog.csdnimg.cn/20210515132653252.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></li>
<li><em>对用例图，要辅佐于一定的用例说明，否则无法根据业务进行代码编写。</em>*</li>
</ul>
<p><img   src="https://img-blog.csdnimg.cn/20210515132707184.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h3 id="功能结构图"   >
          <a href="#功能结构图" class="heading-link"><i class="fas fa-link"></i></a><a href="#功能结构图" class="headerlink" title="功能结构图"></a>功能结构图</h3>
      <p><strong># 注意结构图，要条状清晰，整体对齐</strong><br><img   src="https://img-blog.csdnimg.cn/20210515111102553.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h2 id="系统设计"   >
          <a href="#系统设计" class="heading-link"><i class="fas fa-link"></i></a><a href="#系统设计" class="headerlink" title="系统设计"></a>系统设计</h2>
      
        <h3 id="数据库设计"   >
          <a href="#数据库设计" class="heading-link"><i class="fas fa-link"></i></a><a href="#数据库设计" class="headerlink" title="数据库设计"></a>数据库设计</h3>
      
        <h4 id="实体图"   >
          <a href="#实体图" class="heading-link"><i class="fas fa-link"></i></a><a href="#实体图" class="headerlink" title="实体图"></a>实体图</h4>
      <p><strong>实体图不是E-R图</strong></p>
<p>一般来说，<strong>写了几个实体图，就要有对应的几个E-R图</strong>。</p>
<p><strong>每个字段要知道什么意思！</strong><br><img   src="https://img-blog.csdnimg.cn/20210515132854242.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h4 id="E-R图"   >
          <a href="#E-R图" class="heading-link"><i class="fas fa-link"></i></a><a href="#E-R图" class="headerlink" title="E-R图"></a>E-R图</h4>
      <p>注意，要搞清楚一对多的关系！（<strong>检查数据库，表与表之间的关系。</strong>）</p>
<p><strong>要对应实体图！</strong></p>
<p>一对多，一对一一般不做多的表，多对多要建立新的表。</p>

        <h3 id="时序图"   >
          <a href="#时序图" class="heading-link"><i class="fas fa-link"></i></a><a href="#时序图" class="headerlink" title="时序图"></a>时序图</h3>
      <p><img   src="https://img-blog.csdnimg.cn/20210515133106187.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h2 id="系统实现"   >
          <a href="#系统实现" class="heading-link"><i class="fas fa-link"></i></a><a href="#系统实现" class="headerlink" title="系统实现"></a>系统实现</h2>
      
        <h3 id="代码讲解"   >
          <a href="#代码讲解" class="heading-link"><i class="fas fa-link"></i></a><a href="#代码讲解" class="headerlink" title="代码讲解"></a>代码讲解</h3>
      <p>要<strong>注意找到对应的后台代码</strong></p>
<p><strong>以登录举例：（如果老师问，就在对应的页面操作！）</strong></p>
<ol>
<li>运行代码，按F12，调出控制台<br><img   src="https://img-blog.csdnimg.cn/20210515134136702.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></li>
</ol>
<ol start="2">
<li>点击对应到后台action的事件，看看触发了什么请求方法名？</li>
</ol>
<p><img   src="https://img-blog.csdnimg.cn/20210515134249327.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br><strong>login</strong> 那么在对应后台的Controller中找这个方法！</p>
<p>可以使用快捷键：<code>Ctrl + Shift + R</code> 全局搜索这个RequestMapping</p>
<p><img   src="https://img-blog.csdnimg.cn/20210515134413767.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<ul>
<li>讲代码的时候，不要乱&amp;按照逻辑来讲，尽量编写代码的时候（<strong>见词生意</strong>）</li>
</ul>
<p>==遇到不会的，那就点到为止==</p>
<p><strong>尽量不要贴前端代码，代码不要贴太多，不要超过一页！</strong></p>
<p><img   src="https://img-blog.csdnimg.cn/20210515135042409.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h2 id="系统测试"   >
          <a href="#系统测试" class="heading-link"><i class="fas fa-link"></i></a><a href="#系统测试" class="headerlink" title="系统测试"></a>系统测试</h2>
      <p><strong>要了解常见的测试方法：黑盒测试，白盒测试。</strong></p>
<p>最好附上，<strong>系统测试表。</strong></p>

        <h2 id="总结"   >
          <a href="#总结" class="heading-link"><i class="fas fa-link"></i></a><a href="#总结" class="headerlink" title="总结"></a>总结</h2>
      <ol>
<li>具体开发个什么东西？</li>
<li>开发的过程中，用到什么工具？</li>
<li>开发过程中，遇到什么具体的问题？</li>
<li>未来维护中，怎么解决所遇到的问题？或者整体是否有更好的架构工具！？</li>
</ol>

        <h2 id="参考文献"   >
          <a href="#参考文献" class="heading-link"><i class="fas fa-link"></i></a><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2>
      <p><strong>姓名，参考来源，时间。</strong></p>
<p>不要有其他的特殊符号，中间<strong>一般只有逗号与点</strong><br><img src="https://img-blog.csdnimg.cn/20210515135345263.png" alt="在这里插入图片描述"><br>注意，如果英文参考文献，单词之间间隔过大，可以通过以下办法调整：</p>
<ol>
<li><p><strong>选中这段英文参考文献</strong></p>
</li>
<li><p><strong>右键段落</strong>（Office 2010为例）</p>
</li>
<li><p>中文版式，中选择<strong>允许西文在单词中间换行</strong></p>
</li>
</ol>
<p><img   src="https://img-blog.csdnimg.cn/20210515135810406.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h2 id="致谢"   >
          <a href="#致谢" class="heading-link"><i class="fas fa-link"></i></a><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2>
      <p><strong>检查，不要抄别人的致谢！</strong></p>

        <h2 id="遗留重点"   >
          <a href="#遗留重点" class="heading-link"><i class="fas fa-link"></i></a><a href="#遗留重点" class="headerlink" title="遗留重点"></a>遗留重点</h2>
      <ol>
<li><p>再次熟悉代码</p>
</li>
<li><p>熟悉常见的图（用例图，数据流图，E-R图等等以及其中的概念）</p>
</li>
<li><p>提前检查环境，<strong>数据库+后台+前端页面</strong></p>
</li>
</ol>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/16/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%AD%A6%E4%B9%A0-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/">设计模式学习_观察者模式</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-16</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-18</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">1k</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">7分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="观察者模式-Observer-Pattern"   >
          <a href="#观察者模式-Observer-Pattern" class="heading-link"><i class="fas fa-link"></i></a><a href="#观察者模式-Observer-Pattern" class="headerlink" title="观察者模式 Observer Pattern"></a>观察者模式 Observer Pattern</h1>
      <p><strong>这是一种很好解释：气象监测总部WeatherStation与我们的手机APP PhoneDisplay之间的关系。</strong></p>
<p>我们看天气的时候，数据都是依照<em>最新的数据变化而变化的，而变化的数据，来源于具体发送数据的仪器（比如天气传感器 Weather Sensor）</em></p>
<p>也就是说，我们可以利用这种模式，<strong>来更好地在数据变化后，让所有显示器设备更新数据变化消息。</strong></p>

        <h2 id="关键概念"   >
          <a href="#关键概念" class="heading-link"><i class="fas fa-link"></i></a><a href="#关键概念" class="headerlink" title="关键概念"></a>关键概念</h2>
      <p><strong>1. 观察者模式定义了一种“一对多”的关系。</strong></p>
<p><strong>2. 当这个关系中的“一”，数据发生变化时，其中所依赖的“多”将会自动地进行变化。</strong></p>
<p><img   src="https://img-blog.csdnimg.cn/20210516212737914.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br><strong>解释：</strong></p>
<ol>
<li><p>这里ISubject与IObserver如何体现一对多关系？</p>
</li>
<li><p>为什么PhoneDisplay与TvDisplay要有WeatherStation呢？</p>
</li>
</ol>
<p>对于第一个问题，我们在每个ISubject中，附上一个<code>List&lt;IObserver&gt; observers</code>列表。</p>
<p>对于第二个问题，回答是：我们的显示屏要显示数据变化，<strong>而这些数据来源始终是WeatherStation。</strong></p>
<p>因此，update函数其实要用到WeatherStation的数据。</p>

        <h2 id="代码思路-amp-实现："   >
          <a href="#代码思路-amp-实现：" class="heading-link"><i class="fas fa-link"></i></a><a href="#代码思路-amp-实现：" class="headerlink" title="代码思路&amp;实现："></a>代码思路&amp;实现：</h2>
      <ul>
<li>很简单，如果某一个时刻，WeatherStation中的数据（可以是成员变量）变化了，那么我们就执行notify()来通知List中的每一个Observer。</li>
</ul>
<p>接下来，我们用代码来实现：</p>

        <h3 id="抽象接口层面："   >
          <a href="#抽象接口层面：" class="heading-link"><i class="fas fa-link"></i></a><a href="#抽象接口层面：" class="headerlink" title="抽象接口层面："></a>抽象接口层面：</h3>
      <ol>
<li><p>ISubject.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.inter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ISubject</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(IObserver iObserver)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">remove</span><span class="params">(IObserver iObserver)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">notifyObserver</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure></li>
<li><p>IObserver.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.inter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IObserver</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">update</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>

        <h3 id="具体实现层面"   >
          <a href="#具体实现层面" class="heading-link"><i class="fas fa-link"></i></a><a href="#具体实现层面" class="headerlink" title="具体实现层面"></a>具体实现层面</h3>
      <ol>
<li><p>WeatherStation</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IObserver;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.ISubject;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WeatherStation</span> <span class="keyword">implements</span> <span class="title">ISubject</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//被注册进来的所有观察者</span></span><br><span class="line">    List&lt;IObserver&gt; observers = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//温度变量 当温度变量发生变化时 通知所有观察者</span></span><br><span class="line">    Integer temperature = <span class="number">18</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//将观察者注册进来 其中就是用list add进来</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(IObserver iObserver)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.observers.add(iObserver);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">(IObserver iObserver)</span> </span>&#123;</span><br><span class="line">        observers.remove(iObserver);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//在温度变量发生变化后 每一个观察者通过update方法来得到最新数据</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">notifyObserver</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//通知每一个观察者</span></span><br><span class="line">        <span class="keyword">for</span>(IObserver iObserver: <span class="keyword">this</span>.observers)&#123;</span><br><span class="line">            iObserver.update();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Integer <span class="title">getTemperature</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.temperature;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//模拟实现数据变化</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTemperature</span><span class="params">(Integer temperature)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.temperature = temperature;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
<li><p>PhoneDisplay.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IObserver;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhoneDisplay</span> <span class="keyword">implements</span> <span class="title">IObserver</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    WeatherStation weatherStation; </span><br><span class="line"></span><br><span class="line">    <span class="comment">//我们需要得到变化后的数据信息 因此需要通过构造方法 &lt;绑定&gt; 一个被观察者</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">PhoneDisplay</span><span class="params">(WeatherStation weatherStation)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.weatherStation = weatherStation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过这个被观察者的public get方法 我们才可以知道最新的数据信息</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">update</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;数据发生变化，最新温度为:&quot;</span> + </span><br><span class="line">        <span class="keyword">this</span>.weatherStation.getTemperature());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
<li><p>TvDisplay.java</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IObserver;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TvDisplay</span> <span class="keyword">implements</span> <span class="title">IObserver</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    WeatherStation weatherStation;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//我们需要得到变化后的数据信息 因此需要通过构造方法 &lt;绑定&gt; 一个被观察者</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">TvDisplay</span><span class="params">(WeatherStation weatherStation)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.weatherStation = weatherStation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过这个被观察者的public get方法 我们才可以知道最新的数据信息</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">update</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;数据发生变化，最新温度为:&quot;</span> +</span><br><span class="line">         <span class="keyword">this</span>.weatherStation.getTemperature());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>

        <h3 id="主函数："   >
          <a href="#主函数：" class="heading-link"><i class="fas fa-link"></i></a><a href="#主函数：" class="headerlink" title="主函数："></a>主函数：</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.entity.PhoneDisplay;</span><br><span class="line"><span class="keyword">import</span> com.company.entity.TvDisplay;</span><br><span class="line"><span class="keyword">import</span> com.company.entity.WeatherStation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        WeatherStation weatherStation = <span class="keyword">new</span> WeatherStation();</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//手机显示器实时绑定天气预报站台</span></span><br><span class="line">        PhoneDisplay phoneDisplay = <span class="keyword">new</span> PhoneDisplay(weatherStation);</span><br><span class="line">        <span class="comment">//电视机显示器实时绑定天气预报站台</span></span><br><span class="line">        TvDisplay tvDisplay = <span class="keyword">new</span> TvDisplay(weatherStation);</span><br><span class="line">        </span><br><span class="line">		<span class="comment">//天气预报站台将手机显示器注册进来</span></span><br><span class="line">        weatherStation.add(phoneDisplay); </span><br><span class="line">        <span class="comment">//天气预报站台将电视机显示器注册进来</span></span><br><span class="line">        weatherStation.add(tvDisplay); </span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;天气正常，一直都是：&quot;</span> + </span><br><span class="line">        String.valueOf(weatherStation.getTemperature()) + <span class="string">&quot;摄氏度.&quot;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;某一时刻，数据突然发生变化...&quot;</span>);</span><br><span class="line">        weatherStation.setTemperature(-<span class="number">20</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;天气预报站台准备广播消息！Broadcasting...&quot;</span>);</span><br><span class="line"></span><br><span class="line">        weatherStation.notifyObserver();</span><br><span class="line"></span><br><span class="line">        System.out.print(<span class="string">&quot;手机显示器这边显示：&quot;</span>);</span><br><span class="line">        phoneDisplay.update();</span><br><span class="line"></span><br><span class="line">        System.out.print(<span class="string">&quot;电视机显示器这边显示：&quot;</span>);</span><br><span class="line">        tvDisplay.update();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>


        <h3 id="效果图"   >
          <a href="#效果图" class="heading-link"><i class="fas fa-link"></i></a><a href="#效果图" class="headerlink" title="效果图"></a>效果图</h3>
      <p><img   src="https://img-blog.csdnimg.cn/20210517091903993.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/15/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%AD%A6%E4%B9%A0-%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/">设计模式学习_策略模式</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-15</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-25</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">1k</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">7分</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h1 id="策略者模式-Strategy-Pattern"   >
          <a href="#策略者模式-Strategy-Pattern" class="heading-link"><i class="fas fa-link"></i></a><a href="#策略者模式-Strategy-Pattern" class="headerlink" title="策略者模式 Strategy Pattern"></a>策略者模式 Strategy Pattern</h1>
      
        <h2 id="使用背景"   >
          <a href="#使用背景" class="heading-link"><i class="fas fa-link"></i></a><a href="#使用背景" class="headerlink" title="使用背景"></a>使用背景</h2>
      <ul>
<li>定义： 我们将算法Algorithm与使用者Client分离，让这些使用者自由地选择策略。</li>
</ul>
<p>想象这样一个场景：</p>
<p><strong>有一个基类Duck，它具有两个方法：void eat() 与 void fly()</strong></p>
<p><strong>eat代表吃 fly代表飞行</strong></p>
<p><strong>现在有两个subclass 子类：WildDuck 与 CityDuck</strong></p>
<ol>
<li><p>它们在eat的行为上一摸一样</p>
</li>
<li><p>它们在fly的行为上不一样</p>
</li>
</ol>
<p>试想，如果我们用Java来实现：</p>
<p>整个UML图可能是这样：</p>
<p><img   src="https://img-blog.csdnimg.cn/20210516095210685.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<p><strong>其中，- 代表这是一个私有方法，且void代表它无返回值。</strong></p>
<p><em>前面，我们提到：这两种鸭子的eat行为是一样的，而fly的行为不一样。</em></p>
<p>那么，在这种<strong>单重继承</strong>的情况下，如果eat行为一样，我们只能<strong>重复的复制粘贴代码。</strong></p>
<ul>
<li>想象一下，当子类的数目在需求增大的过程中越来越多？这样的代码不具有高重用性与可维护性。</li>
</ul>

        <h2 id="使用策略者模式解决问题"   >
          <a href="#使用策略者模式解决问题" class="heading-link"><i class="fas fa-link"></i></a><a href="#使用策略者模式解决问题" class="headerlink" title="使用策略者模式解决问题"></a>使用策略者模式解决问题</h2>
      <ol>
<li><p>在上述问题中，eat与fly可以代表两种算法或者策略</p>
</li>
<li><p>使用者就是WildDuck以及CityDuck</p>
</li>
</ol>
<p>我们希望对于不同的使用者，可以任意使用策略。</p>

        <h3 id="解决方案："   >
          <a href="#解决方案：" class="heading-link"><i class="fas fa-link"></i></a><a href="#解决方案：" class="headerlink" title="解决方案："></a>解决方案：</h3>
      <p><strong>我们将同一种策略，封装成接口Interface，然后采用不同的实现策略（即不同的实现类）</strong></p>
<p>同时，将这些接口，注入到我们的使用者中。</p>
<p>使用具体的方法时，我们使用<strong>这些使用者的所注入进来的实现类的具体方法。</strong></p>
<p>直接上UML图：（图不规范，见谅。）</p>
<p><img   src="https://img-blog.csdnimg.cn/20210516100613284.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
<p>从这个图中，我们可以看到：</p>
<ol>
<li><p>Duck类具有两个接口:IEatBehavior与IFlyBehavior</p>
</li>
<li><p>每个接口都有若干个实现类（策略）</p>
</li>
<li><p>当子类WildDuck与CityDuck继承Duck时，具有父类的所有资源。</p>
</li>
</ol>
<ul>
<li>那么如何用代码实现呢？</li>
</ul>

        <h3 id="代码实现："   >
          <a href="#代码实现：" class="heading-link"><i class="fas fa-link"></i></a><a href="#代码实现：" class="headerlink" title="代码实现："></a>代码实现：</h3>
      <ol>
<li>首先，我们要有一个基类 Duck.java以及它的子类 WildDuck.java与CityDuck.java<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IEatBehavior;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.IFlyBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Duck</span> </span>&#123;</span><br><span class="line">    IEatBehavior iEatBehavior;</span><br><span class="line"></span><br><span class="line">    IFlyBehavior iFlyBehavior;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Duck</span><span class="params">(IEatBehavior iEatBehavior, IFlyBehavior iFlyBehavior)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.iEatBehavior = iEatBehavior;</span><br><span class="line">        <span class="keyword">this</span>.iFlyBehavior = iFlyBehavior;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.iEatBehavior.eat();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fly</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.iFlyBehavior.fly();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>
<p><strong>可以看到，这里有两个接口，分别代表两种策略（Eat与Fly）</strong></p>
<p><strong># WildDuck.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IEatBehavior;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.IFlyBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WildDuck</span> <span class="keyword">extends</span> <span class="title">Duck</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">WildDuck</span><span class="params">(IEatBehavior iEatBehavior, IFlyBehavior iFlyBehavior)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(iEatBehavior, iFlyBehavior);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p><strong># CityDuck.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IEatBehavior;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.IFlyBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CityDuck</span> <span class="keyword">extends</span> <span class="title">Duck</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">CityDuck</span><span class="params">(IEatBehavior iEatBehavior, IFlyBehavior iFlyBehavior)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(iEatBehavior, iFlyBehavior);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<ol start="2">
<li>定义两种接口</li>
</ol>
<p><strong># iEatBehavior.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.inter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IEatBehavior</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p><strong># iFlyBehavior.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.inter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IFlyBehavior</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fly</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<ol start="3">
<li>定义这些接口的不同策略实现类</li>
</ol>
<p><strong># SimpleEatBehaviorImpl.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IEatBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleEatBehaviorImpl</span> <span class="keyword">implements</span> <span class="title">IEatBehavior</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;吃：采用正常吃饭的策略！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong># SimpleFlyBehaviorImpl.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IFlyBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleFlyBehaviorImpl</span> <span class="keyword">implements</span> <span class="title">IFlyBehavior</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fly</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;飞：采用正常飞的策略！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p><strong># JetFlyBehaviorImpl.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.inter.IFlyBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JetFlyBehaviorImpl</span> <span class="keyword">implements</span> <span class="title">IFlyBehavior</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fly</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;飞：采用喷气式飞行的策略！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<ul>
<li>那么目前为止，我们已经将这些策略与使用者分离了。</li>
</ul>
<p>使用的时候，我们只需要让他们使用不同的策略即可。</p>
<p><strong># Main.java</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.company.entity.CityDuck;</span><br><span class="line"><span class="keyword">import</span> com.company.entity.WildDuck;</span><br><span class="line"><span class="keyword">import</span> com.company.impl.JetFlyBehaviorImpl;</span><br><span class="line"><span class="keyword">import</span> com.company.impl.SimpleEatBehaviorImpl;</span><br><span class="line"><span class="keyword">import</span> com.company.impl.SimpleFlyBehaviorImpl;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.IEatBehavior;</span><br><span class="line"><span class="keyword">import</span> com.company.inter.IFlyBehavior;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//对于城市Duck来说 Eat采用的是simpleEat策略 Fly也采用的是simpleFly策略</span></span><br><span class="line">        IEatBehavior iSimpleEatBehavior = <span class="keyword">new</span> SimpleEatBehaviorImpl();</span><br><span class="line">        IFlyBehavior iSimpleFlyBehavior = <span class="keyword">new</span> SimpleFlyBehaviorImpl();</span><br><span class="line">        CityDuck cityDuck = <span class="keyword">new</span> CityDuck(iSimpleEatBehavior, iSimpleFlyBehavior);</span><br><span class="line">        System.out.println(<span class="string">&quot;城市鸭子采用的策略：&quot;</span>);</span><br><span class="line">        cityDuck.eat();</span><br><span class="line">        cityDuck.fly();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//对于城市Duck来说 Eat采用的是simpleEat策略（直接重用） Fly采用的是jetFly策略</span></span><br><span class="line">        IFlyBehavior iJetFlyBehavior = <span class="keyword">new</span> JetFlyBehaviorImpl();</span><br><span class="line">        WildDuck wildDuck = <span class="keyword">new</span> WildDuck(iSimpleEatBehavior, iJetFlyBehavior);</span><br><span class="line">        System.out.println(<span class="string">&quot;接下来是野鸭子采用的策略：&quot;</span>);</span><br><span class="line">        wildDuck.eat();</span><br><span class="line">        wildDuck.fly();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p><strong>效果图：</strong></p>
<p><img   src="https://img-blog.csdnimg.cn/20210516102112668.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/blog/2021/05/12/VUE%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95%E5%8F%8A%E7%9B%B8%E5%BA%94%E5%BA%94%E7%94%A8-4/">VUE学习笔记-4-VUE小技巧</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-05-12</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-05-19</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">6.4k</span></span><span class="post-meta-item post-meta-item--readtime"><span class="post-meta-item__icon"><i class="far fa-clock"></i></span><span class="post-meta-item__info">阅读时长</span><span class="post-meta-item__value">53分</span></span></div></header><div class="post-body"><div class="post-excerpt"><!-- 页面必备样式 -->
<style>
.back-top{position: fixed;top: 500px;height: 0px;float: right;right: 50px;}
.back-top>a{font-weight:bold;width: 50px;height: 50px;text-align: center;text-decoration: none;font-size: 5px;line-height: 50px;border-radius: 50px;background-color:rgba(255,255,255,0.5);}
</style>
<div class="back-top">
    <a href="#top"> >返回顶部< </a>
</div>
<!-- toc -->
<!-- 必备样式结束 -->


        <h1 id="axios请求-包括Get请求与Post请求（注意是异步）"   >
          <a href="#axios请求-包括Get请求与Post请求（注意是异步）" class="heading-link"><i class="fas fa-link"></i></a><a href="#axios请求-包括Get请求与Post请求（注意是异步）" class="headerlink" title="axios请求 包括Get请求与Post请求（注意是异步）"></a>axios请求 包括Get请求与Post请求（注意是异步）</h1>
      <p>因为该方法是异步，<strong>因此无法准确知道元素的执行顺序。</strong></p>
<p>有可能axios方法后面的方法会提前执行，也有可能会延后执行。</p>

        <h2 id="Get方法"   >
          <a href="#Get方法" class="heading-link"><i class="fas fa-link"></i></a><a href="#Get方法" class="headerlink" title="Get方法"></a>Get方法</h2>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _this = <span class="built_in">this</span></span><br><span class="line"><span class="keyword">var</span> _data = <span class="built_in">this</span>.$data</span><br><span class="line">axios.get(main.requestAddress + <span class="string">&#x27;/book/showAllBooks&#x27;</span>, &#123;</span><br><span class="line">		<span class="attr">params</span>: &#123;<span class="string">&#x27;pn&#x27;</span>: _data.queryParams.currentPageNum&#125;</span><br><span class="line">	&#125;).then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;</span><br><span class="line">		<span class="comment">//从后端返回给前端的内容(code、message、data...等等)</span></span><br><span class="line">	&#125;).catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">		</span><br><span class="line">	&#125;);</span><br></pre></td></tr></table></div></figure>

<p><strong>params:{ ‘data’: data}</strong> 是指以键值对的方式 往后台传输数据</p>
<p><strong>因此，后台需要用@RequestParam()标签</strong></p>
<p><strong>注意，在main.js中定义一个变量 var requestAddress=”192.xxx.xxx.xxx”</strong></p>
<p>同时<strong>导出这个main.js</strong></p>
<p>最后使用的时候<strong>记得 import main from ‘main.js的路径’</strong></p>

        <h3 id="请务必注意！"   >
          <a href="#请务必注意！" class="heading-link"><i class="fas fa-link"></i></a><a href="#请务必注意！" class="headerlink" title="请务必注意！"></a>请务必注意！</h3>
      <p><strong>使用axios请求时，如果需要用到在回调函数中用到该网页的内容。</strong></p>
<p><strong>必须在axios.get/post方法外 定义一个</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _this = <span class="built_in">this</span></span><br></pre></td></tr></table></div></figure>

<p>注意外面的this与回调函数的this不一样！！！</p>

        <h2 id="Post方法"   >
          <a href="#Post方法" class="heading-link"><i class="fas fa-link"></i></a><a href="#Post方法" class="headerlink" title="Post方法"></a>Post方法</h2>
      <p>POST方法比较复杂，涉及到<strong>数据绑定</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">&lt;el-form :rules=<span class="string">&quot;loginFormRules&quot;</span> ref=<span class="string">&quot;loginForm&quot;</span> </span><br><span class="line">		:model=<span class="string">&quot;loginForm&quot;</span> label-position=<span class="string">&quot;right&quot;</span> </span><br><span class="line">		label-width=<span class="string">&quot;auto&quot;</span> show-message&gt;</span><br><span class="line">		</span><br><span class="line">	<span class="xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;login-title&quot;</span>&gt;</span>欢迎登录<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">	<span class="xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;margin-top: 5px&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">		</span><br><span class="line">	<span class="xml"><span class="tag">&lt;<span class="name">el-form-item</span> <span class="attr">label</span>=<span class="string">&quot;用户名&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;username&quot;</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;<span class="name">el-col</span> <span class="attr">:span</span>=<span class="string">&quot;22&quot;</span>&gt;</span></span></span><br><span class="line"><span class="xml">			<span class="tag">&lt;<span class="name">el-input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;loginForm.username&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-input</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">el-col</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span></span><br><span class="line">	</span><br><span class="line">	<span class="xml"><span class="tag">&lt;<span class="name">el-form-item</span> <span class="attr">label</span>=<span class="string">&quot;密码&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;password&quot;</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;<span class="name">el-col</span> <span class="attr">:span</span>=<span class="string">&quot;22&quot;</span>&gt;</span></span></span><br><span class="line"><span class="xml">			<span class="tag">&lt;<span class="name">el-input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;loginForm.password&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-input</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">el-col</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span></span><br><span class="line">	</span><br><span class="line">	<span class="xml"><span class="tag">&lt;<span class="name">el-form-item</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;<span class="name">el-button</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;loginSubmit(&#x27;loginForm&#x27;)&quot;</span>&gt;</span>登录<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;<span class="name">el-button</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;dialogVisible=true&quot;</span>&gt;</span>注册<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span></span><br><span class="line">			</span><br><span class="line">&lt;/el-form&gt;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p><strong>ref=”loginForm” 与 :model=”loginForm” 都是指绑定data中的loginForm</strong></p>
<p><strong>rules=”loginFormRules” 指的是绑定自定义规则</strong></p>
<p><strong>v-model=”loginForm.username”指的是 该值双向绑定loginForm里面的username属性</strong>因此，一定记得<strong>prop=loginForm.prop</strong></p>
<p>点击登录按钮时，<strong>loginForm</strong>作为参数传进去！</p>
<p><strong>1. loginForm里面的参数-&gt;对应的所有prop</strong></p>
<p>写在<strong>return</strong>里面即可：</p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">loginForm: &#123;</span><br><span class="line">    <span class="attr">username</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">password</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>2. loginForm对应的规则，也写在return里面</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">loginFormRules: &#123;</span><br><span class="line">    <span class="attr">username</span>:[</span><br><span class="line">                &#123;<span class="attr">required</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;账号不可为空&#x27;</span>, <span class="attr">trigger</span>: <span class="string">&#x27;blur&#x27;</span>&#125;</span><br><span class="line">            ],</span><br><span class="line">    <span class="attr">password</span>: [</span><br><span class="line">                &#123;<span class="attr">required</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;密码不可为空&#x27;</span>, <span class="attr">trigger</span>: <span class="string">&#x27;blur&#x27;</span>&#125;</span><br><span class="line">            ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>require表示必须填，触发blur后，会提示message！</strong></p>
<p>这样，在JS中，可以将该表单<strong>loginForm</strong>与它对应的<strong>参数输入规则</strong>绑定在一起验证！</p>
<p>同时也可以自定义验证规则！<br><strong>在data(){这里} 中写</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> validateUserName = <span class="function">(<span class="params">rule, value, callback</span>) =&gt;</span> &#123;</span><br><span class="line">	<span class="keyword">if</span>(value === <span class="number">0</span>)&#123;</span><br><span class="line">		callback(<span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;这里是错误提示&#x27;</span>))	</span><br><span class="line">	&#125;<span class="keyword">else</span>&#123;</span><br><span class="line">		callback() <span class="comment">//验证成功，通过自定义规则！</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>
<p>其中value是对应输入框的值！</p>
<p>callback用来回调</p>
<p><strong>提示对方错误信息</strong> </p>
<p>还是 </p>
<p><strong>让对方通过</strong></p>
<p>这样的话，可以在规则中，<strong>声明走自定义的规则方法：</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">loginFormRules: &#123;</span><br><span class="line">    <span class="attr">username</span>:[</span><br><span class="line">                &#123;<span class="attr">required</span>: <span class="literal">true</span>, <span class="attr">validator</span>: validateUserName,, trigger: <span class="string">&#x27;blur&#x27;</span>&#125;</span><br><span class="line">            ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>其他自定义规则 看官方文档</strong></p>
<p>具体登录+验证方法如下：</p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">loginSubmit</span>(<span class="params">formName</span>)</span> &#123;</span><br><span class="line">	<span class="keyword">let</span> _this = <span class="built_in">this</span></span><br><span class="line">	<span class="comment">// 为表单绑定验证功能</span></span><br><span class="line">	<span class="built_in">this</span>.$refs[formName].validate(<span class="function">(<span class="params">valid</span>) =&gt;</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> (valid) &#123;</span><br><span class="line">			<span class="comment">// 使用 vue-router 路由到指定页面，该方式称之为编程式导航</span></span><br><span class="line">			<span class="built_in">this</span>.$axios.post(main.requestAddress + <span class="string">`/user/login`</span>, _this.loginForm)</span><br><span class="line">				.then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">					_this.$data.message = res.data.message</span><br><span class="line">						<span class="comment">//若数据库查询失败 则返回重新登录信息</span></span><br><span class="line">						<span class="keyword">if</span> (res.data.data === <span class="literal">null</span>) &#123;</span><br><span class="line">							_this.openLoginFailMessage();</span><br><span class="line">							<span class="keyword">return</span>;</span><br><span class="line">						&#125;</span><br><span class="line">						sessionStorage.setItem(<span class="string">&quot;token&quot;</span>, <span class="literal">true</span>);</span><br><span class="line">						sessionStorage.setItem(<span class="string">&quot;username&quot;</span>, res.data.data.username);</span><br><span class="line">						_this.$router.push(<span class="string">&quot;/index&quot;</span>);<span class="comment">//路由跳转至 path=&gt; /index 具体看自己的路由配置</span></span><br><span class="line">					&#125;)</span><br><span class="line">					.catch(<span class="function"><span class="params">Error</span> =&gt;</span> &#123;</span><br><span class="line">						<span class="built_in">console</span>.log(<span class="built_in">Error</span>)</span><br><span class="line">					&#125;)</span><br><span class="line">			&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">				<span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure>



        <h1 id="全局路由配置（基于session的前端权限）"   >
          <a href="#全局路由配置（基于session的前端权限）" class="heading-link"><i class="fas fa-link"></i></a><a href="#全局路由配置（基于session的前端权限）" class="headerlink" title="全局路由配置（基于session的前端权限）"></a>全局路由配置（基于session的前端权限）</h1>
      <p>1.首先搞清楚，除了登录、404..页面，其他的涉及到<strong>必须要先登录的业务数据页面</strong>都是要授权认证的！</p>
<p>2.授权认证，必须要经过<strong>成功登录</strong></p>
<p>3.每次页面进行跳转都要经过权限认证过程！</p>

        <h2 id="配置路由，除了登录页面，其他都要认证"   >
          <a href="#配置路由，除了登录页面，其他都要认证" class="heading-link"><i class="fas fa-link"></i></a><a href="#配置路由，除了登录页面，其他都要认证" class="headerlink" title="配置路由，除了登录页面，其他都要认证"></a>配置路由，除了登录页面，其他都要认证</h2>
      <p><strong>我们给相应涉及业务数据的页面，比如主页面index，加上需要拦截的头信息：</strong></p>
<p><strong>注意！登录页面是不需要加的！</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">	<span class="attr">meta</span>: &#123;</span><br><span class="line">		<span class="attr">requireAuth</span>: <span class="literal">true</span> <span class="comment">//如果来该页面 需要验证</span></span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="attr">path</span>: <span class="string">&#x27;/index&#x27;</span>,</span><br><span class="line">	<span class="attr">name</span>: <span class="string">&#x27;业务逻辑&#x27;</span>,</span><br><span class="line">	<span class="attr">component</span>: <span class="function">()=&gt;</span><span class="keyword">import</span>(<span class="string">&#x27;../views/ShowAll&#x27;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p>然后，在页面拦截时，我们需要判断<strong>要去的页面是否需要授权？</strong></p>
<p><strong>也就是requireAuth是否是’true’？</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//添加全局路由拦截</span></span><br><span class="line">router.beforeEach(<span class="function">(<span class="params">to, <span class="keyword">from</span>, next</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (to.meta.requireAuth) &#123;</span><br><span class="line">        <span class="comment">//如果去的页面需要认证 那么就开始认证</span></span><br><span class="line">        <span class="keyword">if</span> (sessionStorage.getItem(<span class="string">&quot;token&quot;</span>) == <span class="string">&#x27;true&#x27;</span>) &#123;</span><br><span class="line">            next(); <span class="comment">//放行</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            alert(<span class="string">&#x27;请您登陆...&#x27;</span>);</span><br><span class="line">            <span class="comment">//否则下一步也放行 但放行到登录页面</span></span><br><span class="line">            next(&#123;</span><br><span class="line">                <span class="attr">path</span>: <span class="string">&#x27;/login&#x27;</span></span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123; <span class="comment">//如果不需要授权 比如直接去登录页面</span></span><br><span class="line">        <span class="keyword">if</span> (sessionStorage.getItem(<span class="string">&quot;token&quot;</span>) == <span class="string">&#x27;true&#x27;</span> &amp;&amp; to.path != <span class="string">&#x27;/login&#x27;</span>) &#123;</span><br><span class="line">            next(<span class="string">&#x27;/index&#x27;</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            next()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></div></figure>

<ol>
<li><p>注意这里的<strong>sessionStorage.getItem(“token”)<strong>取出来的值是</strong>字符串类型</strong></p>
</li>
<li><p><strong>这里的 &amp;&amp; to.path!=’/login’ 是用户从index主界面 到login登录页面 而不想已经验证但还是跳到index页面的情况</strong> </p>
</li>
<li><p>如果不指定</p>
</li>
</ol>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">next(&#123;<span class="attr">path</span>: <span class="string">&#x27;/login&#x27;</span>&#125;) </span><br></pre></td></tr></table></div></figure>

<p>即<strong>指定去登录页面（前提是登录页面的path是’/login’）</strong>，</p>
<p>那么next()就代表<strong>允许去想要去的页面</strong></p>
<ol start="4">
<li>因为每次我们要看<strong>sessionStorage.getItem(“token”)<strong>里面值是不是’true’。因此，我们需要在登录成功的时候！添加对应的</strong>token</strong>信息</li>
</ol>

        <h2 id="登录成功添加可“允许通过”的路由信息（Token，Session，Cookies均可）"   >
          <a href="#登录成功添加可“允许通过”的路由信息（Token，Session，Cookies均可）" class="heading-link"><i class="fas fa-link"></i></a><a href="#登录成功添加可“允许通过”的路由信息（Token，Session，Cookies均可）" class="headerlink" title="登录成功添加可“允许通过”的路由信息（Token，Session，Cookies均可）"></a>登录成功添加可“允许通过”的路由信息（Token，Session，Cookies均可）</h2>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sessionStorage.setItem(<span class="string">&quot;token&quot;</span>, <span class="literal">true</span>);</span><br></pre></td></tr></table></div></figure>


        <h2 id="过滤路由显示菜单"   >
          <a href="#过滤路由显示菜单" class="heading-link"><i class="fas fa-link"></i></a><a href="#过滤路由显示菜单" class="headerlink" title="过滤路由显示菜单"></a>过滤路由显示菜单</h2>
      <p><strong>如果在菜单中不想让某些通用模块出现（比如登录、注册、注销等功能）</strong></p>
<p><strong>可以在对应路由信息中，添加属性: <code>hidden: true</code></strong></p>
<ul>
<li>在页面中的el-submenu 以及el-submenu-item中 去for循环遍历时，加一个v-if=”!item.hidden” </li>
</ul>
<p><mark> 注意，v-if 与 v-for 是不能同时出现在属性中 可以将v-for 提前一个标签！</mark></p>

        <h1 id="Vue-项目中加入常用插件"   >
          <a href="#Vue-项目中加入常用插件" class="heading-link"><i class="fas fa-link"></i></a><a href="#Vue-项目中加入常用插件" class="headerlink" title="Vue 项目中加入常用插件"></a>Vue 项目中加入常用插件</h1>
      
        <h2 id="加入插件"   >
          <a href="#加入插件" class="heading-link"><i class="fas fa-link"></i></a><a href="#加入插件" class="headerlink" title="加入插件"></a>加入插件</h2>
      <p><strong>通常，我们通过vue/cli来创建相应的vue项目</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vue create vue_demo</span><br></pre></td></tr></table></div></figure>

<ul>
<li>注意，如果不想要VUE严格的eslint语法规则。</li>
</ul>
<p><strong>可以在创建的时候，取消勾选Fomatter。</strong></p>
<p><strong>若需要VUEX全局状态管理，可以勾选。</strong></p>
<p><strong>若需要路由router，则可以选择勾选。</strong></p>
<p>…在经过漫长的cmd后</p>
<p>不用关闭当前<strong>git bash</strong>或者<strong>命令行控制工具Command</strong></p>
<p>我们首先进入这个项目，直接利用npm配置一些插件。</p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cd vue_demo</span><br><span class="line">vue add vuetify <span class="comment">//下载vuetify移动自适应插件</span></span><br><span class="line">vue add element <span class="comment">//引入elementUI 并且在接下来选择时Fully import还是按需引入</span></span><br><span class="line">vue add axios <span class="comment">//将ajax封装好的axios</span></span><br></pre></td></tr></table></div></figure>

<p><strong>不出意外的话，在具体的项目目录中，可以看到多出一个文件夹plugins。</strong></p>
<p><strong>这里装着我们安装进去的插件。</strong></p>
<p>在配置之后，我们可以用VS code来打开这个文件夹，并且</p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run serve</span><br></pre></td></tr></table></div></figure>

<p>运行项目</p>

        <h1 id="VUE中添加Echarts可视化图表"   >
          <a href="#VUE中添加Echarts可视化图表" class="heading-link"><i class="fas fa-link"></i></a><a href="#VUE中添加Echarts可视化图表" class="headerlink" title="VUE中添加Echarts可视化图表"></a>VUE中添加Echarts可视化图表</h1>
      
        <h2 id="npm-安装echarts插件"   >
          <a href="#npm-安装echarts插件" class="heading-link"><i class="fas fa-link"></i></a><a href="#npm-安装echarts插件" class="headerlink" title="npm 安装echarts插件"></a>npm 安装echarts插件</h2>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install echarts --save</span><br></pre></td></tr></table></div></figure>

<p><strong>如果npm的安装速度较慢，可以使用cnpm淘宝镜像</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">//安装淘宝镜像</span></span><br><span class="line">npm install -g cnpm --registry=https:<span class="comment">//registry.npm.taobao.org</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//从淘宝镜像下载</span></span><br><span class="line">cnpm install echarts -S</span><br></pre></td></tr></table></div></figure>

<p><strong>当完成npm安装后，echarts插件出现在 node_modules 目录下</strong></p>

        <h2 id="全局引入ECHARTS"   >
          <a href="#全局引入ECHARTS" class="heading-link"><i class="fas fa-link"></i></a><a href="#全局引入ECHARTS" class="headerlink" title="全局引入ECHARTS"></a>全局引入ECHARTS</h2>
      <p><strong>main.js 文件</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 引入echarts</span></span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> echarts <span class="keyword">from</span> <span class="string">&#x27;echarts&#x27;</span></span><br><span class="line"></span><br><span class="line">Vue.prototype.$echarts = echarts</span><br></pre></td></tr></table></div></figure>


        <h2 id="初始化图表"   >
          <a href="#初始化图表" class="heading-link"><i class="fas fa-link"></i></a><a href="#初始化图表" class="headerlink" title="初始化图表"></a>初始化图表</h2>
      <figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span>  <span class="attr">ref</span>=<span class="string">&quot;chartColumn&quot;</span> <span class="attr">style</span>=<span class="string">&quot;&#123;width: &#x27;300px&#x27;, height: &#x27;300px&#x27;&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<ol>
<li><p>ref属性是为了<strong>JS代码中能引用这个图表</strong></p>
</li>
<li><p><code>&lt;div&gt;</code>属性之间默认隔行 如果想要多个图表在同一行中显示 添加属性：<code>style=&quot;display: inline-block&quot;</code></p>
</li>
<li><p>如果想要动态改变 图表的高度与宽度 <strong>可以利用VUE的动态绑定</strong></p>
</li>
</ol>

        <h2 id="JS画图动态渲染（柱状图与饼状图）"   >
          <a href="#JS画图动态渲染（柱状图与饼状图）" class="heading-link"><i class="fas fa-link"></i></a><a href="#JS画图动态渲染（柱状图与饼状图）" class="headerlink" title="JS画图动态渲染（柱状图与饼状图）"></a>JS画图动态渲染（柱状图与饼状图）</h2>
      
        <h3 id="饼状图"   >
          <a href="#饼状图" class="heading-link"><i class="fas fa-link"></i></a><a href="#饼状图" class="headerlink" title="饼状图"></a>饼状图</h3>
      <p><strong>将画图抽象成一个函数 <code>drawLine()</code> 这个函数放在mounted() 生命周期函数中</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.drawLine();</span><br></pre></td></tr></table></div></figure>

<p><strong>图标参数JSON数据 （定义在data中的return{}）</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">optionCircle:&#123;</span><br><span class="line">                    <span class="attr">title</span>: &#123;</span><br><span class="line">                        <span class="attr">text</span>: <span class="string">&#x27;实时热门图书&#x27;</span>,</span><br><span class="line">                        <span class="attr">subtext</span>: <span class="string">&#x27;站点动态统计&#x27;</span>,</span><br><span class="line">                        <span class="attr">left</span>: <span class="string">&#x27;center&#x27;</span></span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">tooltip</span>: &#123;</span><br><span class="line">                        <span class="attr">trigger</span>: <span class="string">&#x27;item&#x27;</span></span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">legend</span>: &#123;</span><br><span class="line">                        <span class="attr">orient</span>: <span class="string">&#x27;vertical&#x27;</span>,</span><br><span class="line">                        <span class="attr">left</span>: <span class="string">&#x27;left&#x27;</span>,</span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">series</span>: [</span><br><span class="line">                        &#123;</span><br><span class="line">                            <span class="attr">name</span>: <span class="string">&#x27;访问来源&#x27;</span>,</span><br><span class="line">                            <span class="attr">type</span>: <span class="string">&#x27;pie&#x27;</span>,</span><br><span class="line">                            <span class="attr">radius</span>: <span class="string">&#x27;50%&#x27;</span>,</span><br><span class="line">                            <span class="attr">data</span>: [],</span><br><span class="line">                            <span class="attr">emphasis</span>: &#123;</span><br><span class="line">                                <span class="attr">itemStyle</span>: &#123;</span><br><span class="line">                                    <span class="attr">shadowBlur</span>: <span class="number">10</span>,</span><br><span class="line">                                    <span class="attr">shadowOffsetX</span>: <span class="number">0</span>,</span><br><span class="line">                                    <span class="attr">shadowColor</span>: <span class="string">&#x27;rgba(0, 0, 0, 0.5)&#x27;</span></span><br><span class="line">                                &#125;</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                    ]</span><br><span class="line">                &#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>正常情况下，是看不到任何数据的 但是能看到你的饼状图标题</strong></p>
<p><strong>接下来，我们要在data中从后台动态添加数据</strong></p>
<p><strong>这里我选择 AXIOS 异步刷新数据</strong></p>
<p><strong>JS drawLine() 函数</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">drawLine</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">	 <span class="comment">// 基于准备好的dom，初始化echarts实例</span></span><br><span class="line">	 <span class="comment">//通过ref来找到图表</span></span><br><span class="line">	<span class="keyword">let</span> myChartCircle = <span class="built_in">this</span>.$echarts.init(<span class="built_in">this</span>.$refs.chartCircle);</span><br><span class="line"></span><br><span class="line">	<span class="comment">//动态从数据库中取数据</span></span><br><span class="line">	<span class="comment">//画饼图</span></span><br><span class="line">	<span class="keyword">const</span> _this = <span class="built_in">this</span></span><br><span class="line">	axios.get(</span><br><span class="line">		main.requestAddress +</span><br><span class="line">		<span class="string">&#x27;/book/showPopularBooks&#x27;</span>).then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;</span><br><span class="line">		<span class="keyword">let</span> list = response.data.data</span><br><span class="line">		<span class="keyword">let</span> data = _this.$data.optionCircle.series[<span class="number">0</span>].data</span><br><span class="line"></span><br><span class="line">		<span class="keyword">for</span>(<span class="keyword">let</span> i =<span class="number">0</span>; i&lt;list.length; i++)&#123;</span><br><span class="line">			data.push(&#123;</span><br><span class="line">				<span class="attr">name</span>: list[i].bookname,</span><br><span class="line">				<span class="attr">value</span>: list[i].borrowNum</span><br><span class="line">			&#125;)</span><br><span class="line">		&#125;</span><br><span class="line">		myChartCircle.setOption(_this.$data.optionCircle);</span><br><span class="line">	&#125;).catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">		alert(error);</span><br><span class="line">	&#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>可以看到，其实真正的饼状图数据是：</strong></p>
<p><strong>“name”代表饼图的名称 “value”代表对应name的饼图数据</strong></p>
<p><strong>值得注意的是，这种push方法是加入新的JSON对象的方法</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">data.push(&#123;</span><br><span class="line">	<span class="attr">key1</span>: value1(可以来自后台),</span><br><span class="line">	<span class="attr">key2</span>: value2(可以来自后台),</span><br><span class="line">	...</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></div></figure>


<p><strong>效果图如下：</strong></p>
<p><img   src="https://img-blog.csdnimg.cn/20210416123833199.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h3 id="柱状图"   >
          <a href="#柱状图" class="heading-link"><i class="fas fa-link"></i></a><a href="#柱状图" class="headerlink" title="柱状图"></a>柱状图</h3>
      <p><strong>与饼状图相似，先是配置图标参数，渲染图表，最后是取数据</strong></p>

        <h4 id="配置图表参数"   >
          <a href="#配置图表参数" class="heading-link"><i class="fas fa-link"></i></a><a href="#配置图表参数" class="headerlink" title="配置图表参数"></a>配置图表参数</h4>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">optionColumn:&#123;</span><br><span class="line">		<span class="attr">title</span>: &#123;</span><br><span class="line">			<span class="attr">text</span>: <span class="string">&#x27;实时借书用户&#x27;</span></span><br><span class="line">		&#125;,</span><br><span class="line">		<span class="attr">tooltip</span>: &#123;</span><br><span class="line">		&#125;,</span><br><span class="line">		<span class="attr">legend</span>: &#123;</span><br><span class="line">		&#125;,</span><br><span class="line">		<span class="attr">xAxis</span>: &#123;</span><br><span class="line">			<span class="attr">data</span>: []</span><br><span class="line">		&#125;,</span><br><span class="line">		<span class="attr">yAxis</span>: &#123;&#125;,</span><br><span class="line">		<span class="attr">series</span>: [&#123;</span><br><span class="line">			<span class="attr">name</span>: <span class="string">&#x27;借阅次数&#x27;</span>,</span><br><span class="line">			<span class="attr">type</span>: <span class="string">&#x27;bar&#x27;</span>,</span><br><span class="line">			<span class="attr">data</span>: []</span><br><span class="line">		&#125;]</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></div></figure>


        <h4 id="渲染图表"   >
          <a href="#渲染图表" class="heading-link"><i class="fas fa-link"></i></a><a href="#渲染图表" class="headerlink" title="渲染图表"></a>渲染图表</h4>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> myChartColumn = <span class="built_in">this</span>.$echarts.init(<span class="built_in">this</span>.$refs.chartColumn)</span><br><span class="line">	<span class="comment">//使用刚指定的配置项和数据显示图表。</span></span><br><span class="line">	<span class="comment">//画柱状图</span></span><br><span class="line">	axios.get(</span><br><span class="line">		main.requestAddress +</span><br><span class="line">		<span class="string">&#x27;/book/showPopularUsers&#x27;</span>).then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;</span><br><span class="line">		<span class="keyword">let</span> list = response.data.data</span><br><span class="line">		<span class="keyword">let</span> nameArray = _this.$data.optionColumn.xAxis.data</span><br><span class="line">		<span class="keyword">let</span> numArray = _this.$data.optionColumn.series[<span class="number">0</span>].data</span><br><span class="line">		<span class="keyword">for</span>(<span class="keyword">let</span> i=<span class="number">0</span>; i&lt;list.length; i++)&#123;</span><br><span class="line">			nameArray.push(list[i].username);</span><br><span class="line">			numArray.push(list[i].totalBorrowNum);</span><br><span class="line">		&#125;</span><br><span class="line">		myChartColumn.setOption(_this.$data.optionColumn);</span><br><span class="line"></span><br><span class="line">	&#125;).catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">		alert(error);</span><br><span class="line">	&#125;);</span><br></pre></td></tr></table></div></figure>

<p><strong>可以看到，对于柱状图，我们要配置两个</strong></p>
<ol>
<li><p>xAxis 即X轴的数组中的数据</p>
</li>
<li><p>series[0]中的data数组 代表从左往右依次的 棱柱所代表的value</p>
</li>
</ol>
<p><strong>效果图如下</strong></p>
<p><img   src="https://img-blog.csdnimg.cn/2021041612451596.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"></p>

        <h1 id="VUEX-存值与取值区域"   >
          <a href="#VUEX-存值与取值区域" class="heading-link"><i class="fas fa-link"></i></a><a href="#VUEX-存值与取值区域" class="headerlink" title="VUEX 存值与取值区域"></a>VUEX 存值与取值区域</h1>
      <p><strong>在VUE中，如果有些数据我们不太需要后台频繁的查询数据</strong></p>
<p>我们就可以将这些数据<strong>存放在VUEX中</strong></p>

        <h2 id="声明store的index-js"   >
          <a href="#声明store的index-js" class="heading-link"><i class="fas fa-link"></i></a><a href="#声明store的index-js" class="headerlink" title="声明store的index.js"></a>声明store的index.js</h2>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">&#x27;vuex&#x27;</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="comment">//导出之后 外部可以使用</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">	<span class="attr">state</span>:&#123;</span><br><span class="line">		<span class="comment">//放全局变量 比如viewCounter是浏览量统计器</span></span><br><span class="line">		viewCounter = <span class="number">1</span></span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="attr">mutations</span>:&#123;</span><br><span class="line">		<span class="comment">//setter方法区域</span></span><br><span class="line">		<span class="function"><span class="title">setViewCounter</span>(<span class="params">state, viewCounter</span>)</span>&#123;</span><br><span class="line">			state.viewCounter = viewCounter </span><br><span class="line">		&#125;</span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="attr">getters</span>:&#123;</span><br><span class="line">		<span class="comment">//getter方法区域</span></span><br><span class="line">		<span class="attr">getViewCounter</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.viewCounter</span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="attr">action</span>:&#123;&#125;,</span><br><span class="line">	<span class="attr">modules</span>:&#123;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>



        <h2 id="在需要存值、取值的地方-调用方法"   >
          <a href="#在需要存值、取值的地方-调用方法" class="heading-link"><i class="fas fa-link"></i></a><a href="#在需要存值、取值的地方-调用方法" class="headerlink" title="在需要存值、取值的地方 调用方法"></a>在需要存值、取值的地方 调用方法</h2>
      
        <h3 id="取值getViewCounter"   >
          <a href="#取值getViewCounter" class="heading-link"><i class="fas fa-link"></i></a><a href="#取值getViewCounter" class="headerlink" title="取值getViewCounter"></a>取值getViewCounter</h3>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.$store.getters.getViewCounter</span><br></pre></td></tr></table></div></figure>


        <h3 id="存值setViewCounter方法"   >
          <a href="#存值setViewCounter方法" class="heading-link"><i class="fas fa-link"></i></a><a href="#存值setViewCounter方法" class="headerlink" title="存值setViewCounter方法"></a>存值setViewCounter方法</h3>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.$store.commit(<span class="string">&#x27;setViewCounter&#x27;</span>, newValue);</span><br></pre></td></tr></table></div></figure>


        <h1 id="WEB项目实现文件下载与上传"   >
          <a href="#WEB项目实现文件下载与上传" class="heading-link"><i class="fas fa-link"></i></a><a href="#WEB项目实现文件下载与上传" class="headerlink" title="WEB项目实现文件下载与上传"></a>WEB项目实现文件下载与上传</h1>
      
        <h2 id="SSM项目-非MultipartFile类"   >
          <a href="#SSM项目-非MultipartFile类" class="heading-link"><i class="fas fa-link"></i></a><a href="#SSM项目-非MultipartFile类" class="headerlink" title="SSM项目+非MultipartFile类"></a>SSM项目+非MultipartFile类</h2>
      <ul>
<li>在这种类型的项目中，我们需要在相应的Spring MVC.xml配置文件中，去配置一个Bean</li>
</ul>
<p>代码如下：</p>
<figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;multipartResolver&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.web.multipart.commons.CommonsMultipartResolver&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;maxUploadSize&quot;</span> <span class="attr">value</span>=<span class="string">&quot;104857600&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;maxInMemorySize&quot;</span> <span class="attr">value</span>=<span class="string">&quot;4096&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;defaultEncoding&quot;</span> <span class="attr">value</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p>这种，我们就可以在Controller层中，使用@RequestParam(“file”) MultipartFile file了。</p>
<p>如果前端是Form表单的话，则前端代码如下：</p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">class</span>=<span class="string">&quot;form-horizontal &quot;</span> <span class="attr">action</span>=<span class="string">&quot;/UploadServlet&quot;</span> <span class="attr">id</span>=<span class="string">&quot;upload&quot;</span> <span class="attr">enctype</span>=<span class="string">&quot;multipart/form-data&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">input</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">type</span>=<span class="string">&quot;file&quot;</span>&gt;</span></span><br><span class="line">	 <span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-success btn-sm&quot;</span>&gt;</span>上传<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">	 <span class="tag">&lt;<span class="name">div</span>&gt;</span> $&#123; message &#125; <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p><strong>这样，当我们点击上传后，即会跳转到对应的action，我们用@PostMapping来接收即可。</strong></p>
<p>后台代码如下：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">	<span class="comment">// 上传文件存储目录</span></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String UPLOAD_DIRECTORY = <span class="string">&quot;upload&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="comment">// 上传配置</span></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MEMORY_THRESHOLD = <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">3</span>;  <span class="comment">// 3MB</span></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MAX_FILE_SIZE = <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">40</span>; <span class="comment">// 40MB</span></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MAX_REQUEST_SIZE = <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">50</span>; <span class="comment">// 50MB</span></span><br><span class="line">   </span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;/UploadServlet&quot;, method = RequestMethod.POST)</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> String <span class="title">upload</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">           ModelAndView modelAndView,</span></span></span><br><span class="line"><span class="params"><span class="function">           HttpServletRequest request,</span></span></span><br><span class="line"><span class="params"><span class="function">           HttpServletResponse response)</span> <span class="keyword">throws</span> IOException, ServletException </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">       <span class="comment">// 配置上传参数</span></span><br><span class="line">       DiskFileItemFactory factory = <span class="keyword">new</span> DiskFileItemFactory();</span><br><span class="line">       <span class="comment">// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中</span></span><br><span class="line">       factory.setSizeThreshold(MEMORY_THRESHOLD);</span><br><span class="line">       <span class="comment">// 设置临时存储目录</span></span><br><span class="line">       factory.setRepository(<span class="keyword">new</span> File(System.getProperty(<span class="string">&quot;java.io.tmpdir&quot;</span>)));</span><br><span class="line"></span><br><span class="line">       ServletFileUpload upload = <span class="keyword">new</span> ServletFileUpload(factory);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 设置最大文件上传值</span></span><br><span class="line">       upload.setFileSizeMax(MAX_FILE_SIZE);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 设置最大请求值 (包含文件和表单数据)</span></span><br><span class="line">       upload.setSizeMax(MAX_REQUEST_SIZE);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 中文处理</span></span><br><span class="line">       upload.setHeaderEncoding(<span class="string">&quot;UTF-8&quot;</span>);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 构造临时路径来存储上传的文件</span></span><br><span class="line">       <span class="comment">// 这个路径相对当前应用的目录</span></span><br><span class="line">       String uploadPath = request.getServletContext().getRealPath(<span class="string">&quot;./&quot;</span>) + File.separator + UPLOAD_DIRECTORY;</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 如果目录不存在则创建</span></span><br><span class="line">       File uploadDir = <span class="keyword">new</span> File(uploadPath);</span><br><span class="line">       <span class="keyword">if</span> (!uploadDir.exists()) &#123;</span><br><span class="line">           uploadDir.mkdir();</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">           List&lt;FileItem&gt; formItems = upload.parseRequest(request);</span><br><span class="line">           <span class="keyword">if</span> (formItems != <span class="keyword">null</span> &amp;&amp; formItems.size() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">               <span class="comment">// 迭代表单数据</span></span><br><span class="line">               <span class="keyword">for</span> (FileItem item : formItems) &#123;</span><br><span class="line">                   <span class="comment">// 处理不在表单中的字段</span></span><br><span class="line">                   <span class="keyword">if</span> (!item.isFormField()) &#123;</span><br><span class="line">                       String fileName = <span class="keyword">new</span> File(item.getName()).getName();</span><br><span class="line">                       String filePath = uploadPath + File.separator + fileName;</span><br><span class="line">                       File storeFile = <span class="keyword">new</span> File(filePath);</span><br><span class="line"></span><br><span class="line">                       <span class="comment">// 在控制台输出文件的上传路径</span></span><br><span class="line">                       String filePathSaved = uploadPath + File.separator;</span><br><span class="line"></span><br><span class="line">                       <span class="comment">// 保存文件到硬盘</span></span><br><span class="line">                       item.write(storeFile);</span><br><span class="line">                       teacherServer.saveFilePath(filePathSaved, fileName);</span><br><span class="line">                       request.setAttribute(<span class="string">&quot;message&quot;</span>, formItems.get(<span class="number">0</span>).getName() + <span class="string">&quot;文件上传成功!&quot;</span>);</span><br><span class="line">                   &#125;</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125; <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line">           request.setAttribute(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;错误信息: &quot;</span> + <span class="string">&quot;文件上传失败，请检查是否文件为空！&quot;</span>);</span><br><span class="line"></span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> <span class="string">&quot;/teacher/tea_add_paper&quot;</span>;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>注意到return这里，我们需要配置相应的视图解析器，不然我们不知道return哪个地方去显示。</strong></p>
<figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--配置试图解析--&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span> = <span class="string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;prefix&quot;</span> <span class="attr">value</span>=<span class="string">&quot;/&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;suffix&quot;</span> <span class="attr">value</span>=<span class="string">&quot;.jsp&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p><img   src="https://img-blog.csdnimg.cn/20210514102019792.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70" style="width: image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tepx;height: t_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNDQ1MDY3,size_16,color_FFFFFF,t_70px;"  alt="在这里插入图片描述"><br><strong>注意：webapp 就是我们配置的根目录，并且配置的视图后缀为.jsp</strong></p>
<ul>
<li>这样我们就能在，相应的视图中，看到message的内容了</li>
</ul>

        <h2 id="SpringBoot项目-JSP-MultipartFile（非AJAX异步）"   >
          <a href="#SpringBoot项目-JSP-MultipartFile（非AJAX异步）" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringBoot项目-JSP-MultipartFile（非AJAX异步）" class="headerlink" title="SpringBoot项目+JSP+MultipartFile（非AJAX异步）"></a>SpringBoot项目+JSP+MultipartFile（非AJAX异步）</h2>
      <p><strong>首先，我们需要在SpringBoot的配置文件application.yml或者application.properties中配置：</strong></p>
<p><strong>application.properties</strong></p>
<figure class="highlight yml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">spring.servlet.multipart.max-request-size=10MB</span></span><br><span class="line"></span><br><span class="line"><span class="string">spring.servlet.multipart.max-file-size=10MB</span></span><br></pre></td></tr></table></div></figure>

<p><strong>然后我们，在controller中写相应语句：</strong></p>
<ul>
<li>我们仍然需要配置视图解析器ViewResolver：</li>
</ul>
<p><strong>在application.properties中：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">spring.mvc.view.prefix=/</span><br><span class="line"></span><br><span class="line">spring.mvc.view.suffix=.jsp</span><br></pre></td></tr></table></div></figure>
<p>仍与上方图片中的项目结构图一致！</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String UPLOAD_DIRECTORY = <span class="string">&quot;upload&quot;</span>;</span><br><span class="line">   </span><br><span class="line"><span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line">   <span class="meta">@ResponseBody</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> String <span class="title">upload</span><span class="params">(<span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file, HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">if</span> (file.isEmpty()) &#123;</span><br><span class="line">       	request.setAttribute(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;对不起，检测到文件为空！&quot;</span>);</span><br><span class="line">           <span class="keyword">return</span> <span class="string">&quot;/teacher/tea_add_paper&quot;</span>;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       String fileName = file.getOriginalFilename();</span><br><span class="line">       String templatePath = request.getServletContext().getRealPath(<span class="string">&quot;./&quot;</span>) + File.separator + UPLOAD_DIRECTORY;</span><br><span class="line"></span><br><span class="line">       File dest = <span class="keyword">new</span> File(filePath + fileName);</span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">           file.transferTo(dest);</span><br><span class="line">           request.setAttribute(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;文件上传成功！&quot;</span>);</span><br><span class="line">           <span class="keyword">return</span> <span class="string">&quot;/teacher/tea_add_paper&quot;</span>;</span><br><span class="line">       &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">       	System.out.println(e)</span><br><span class="line">       &#125;</span><br><span class="line">       </span><br><span class="line">       request.setAttribute(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;文件上传失败！&quot;</span>);</span><br><span class="line">       <span class="keyword">return</span> <span class="string">&quot;/teacher/tea_add_paper&quot;</span>;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>接下来，就准备写前端页面请求：</strong></p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span> <span class="attr">action</span>=<span class="string">&quot;/uploading&quot;</span> <span class="attr">enctype</span>=<span class="string">&quot;multipart/form-data&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;file&quot;</span> <span class="attr">name</span>=<span class="string">&quot;file&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;提交给服务器&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">    	$&#123;message&#125;</span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="SpringBoot-VUE-ElementUI前后端分离"   >
          <a href="#SpringBoot-VUE-ElementUI前后端分离" class="heading-link"><i class="fas fa-link"></i></a><a href="#SpringBoot-VUE-ElementUI前后端分离" class="headerlink" title="SpringBoot+VUE+ElementUI前后端分离"></a>SpringBoot+VUE+ElementUI前后端分离</h2>
      <p><strong>前提是解决跨域问题，并且直接通过IP地址访问，将这个访问的ip地址存在VUEX中或者Main.js中即可。</strong></p>
<p><strong>1. VUE前端页面</strong></p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-upload</span></span></span><br><span class="line"><span class="tag">            <span class="attr">class</span>=<span class="string">&quot;uploadDemo&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">ref</span>=<span class="string">&quot;upload&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">accept</span>=<span class="string">&quot;.doc&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">action</span>=<span class="string">&quot;https://jsonplaceholder.typicode.com/posts/&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">:on-preview</span>=<span class="string">&quot;handlePreview&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">:on-remove</span>=<span class="string">&quot;handleRemove&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">:http-request</span>=<span class="string">&quot;httpRequest&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">:auto-upload</span>=<span class="string">&quot;false&quot;</span></span></span><br><span class="line"><span class="tag">          &gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-button</span> <span class="attr">slot</span>=<span class="string">&quot;trigger&quot;</span> <span class="attr">size</span>=<span class="string">&quot;small&quot;</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span></span></span><br><span class="line"><span class="tag">              &gt;</span>选取文件&lt;/el-button</span><br><span class="line">            &gt;</span><br><span class="line">            <span class="tag">&lt;<span class="name">el-button</span></span></span><br><span class="line"><span class="tag">              <span class="attr">style</span>=<span class="string">&quot;margin-left: 10px&quot;</span></span></span><br><span class="line"><span class="tag">              <span class="attr">size</span>=<span class="string">&quot;small&quot;</span></span></span><br><span class="line"><span class="tag">              <span class="attr">type</span>=<span class="string">&quot;success&quot;</span></span></span><br><span class="line"><span class="tag">              @<span class="attr">click</span>=<span class="string">&quot;submitUpload&quot;</span></span></span><br><span class="line"><span class="tag">              &gt;</span>上传到服务器&lt;/el-button</span><br><span class="line">            &gt;</span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> <span class="attr">slot</span>=<span class="string">&quot;tip&quot;</span> <span class="attr">class</span>=<span class="string">&quot;el-upload__tip&quot;</span>&gt;</span></span><br><span class="line">              只能上传.doc后缀文件，且不超过40MB</span><br><span class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="name">el-upload</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<ol start="2">
<li>写两个函数</li>
</ol>
<p><strong>一个是按钮点击函数，另一个是上传文件的表单具体提交（axios请求）的函数</strong></p>
<ul>
<li>提交按钮函数<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">submitUpload</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.$refs.upload.submit(); <span class="comment">//我们通过el-upload的引用来找到 并让他提交</span></span><br><span class="line">    &#125;,</span><br></pre></td></tr></table></div></figure></li>
</ul>
<p><strong>注意，我们这里看到他的action位置，并不是我们的后台地址。</strong></p>
<p><strong>也就是说，我们通过先把自己的文件传给他的action，再由他的action服务器地址，传给我们的后台服务器。</strong></p>
<p><strong>最后，提交表单后，会走绑定属性httpRequest的方法，即：</strong></p>
<ul>
<li>表单提交函数<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//最后上传走这个方法！</span></span><br><span class="line">    <span class="function"><span class="title">httpRequest</span>(<span class="params">param</span>)</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> fileObj = param.file; <span class="comment">// 相当于input里取得的files</span></span><br><span class="line">      <span class="keyword">let</span> data = <span class="keyword">new</span> FormData(); <span class="comment">// FormData 对象</span></span><br><span class="line">      data.append(<span class="string">&quot;file&quot;</span>, fileObj); <span class="comment">// 文件对象 后台用@RequestParam来接收</span></span><br><span class="line">      <span class="keyword">const</span> config = &#123; <span class="attr">headers</span>: &#123; <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;multipart/form-data&quot;</span> &#125; &#125;;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> _this = <span class="built_in">this</span>;</span><br><span class="line">	  <span class="comment">//在这里我将后台的服务器地址 存进了VUEX中</span></span><br><span class="line">	  <span class="comment">//并通过相应的getters 来获取</span></span><br><span class="line">      <span class="built_in">this</span>.$axios</span><br><span class="line">        .post(</span><br><span class="line">          <span class="built_in">this</span>.$store.getters.getRequestAddress + <span class="string">`/uploading`</span>,</span><br><span class="line">          data,</span><br><span class="line">          config</span><br><span class="line">        )</span><br><span class="line">        .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">let</span> data = res.data;</span><br><span class="line">          <span class="built_in">console</span>.log(data);</span><br><span class="line">          <span class="keyword">if</span> (data.data === <span class="number">1</span>) &#123;</span><br><span class="line">            _this.sendMessage(data.message, <span class="string">&quot;success&quot;</span>);</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            _this.sendMessage(data.message, <span class="string">&quot;error&quot;</span>);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">        .catch(<span class="function">(<span class="params"><span class="built_in">Error</span></span>) =&gt;</span> &#123;</span><br><span class="line">          _this.sendMessage(<span class="string">&quot;请求失败！&quot;</span>, <span class="string">&quot;error&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;,</span><br></pre></td></tr></table></div></figure></li>
</ul>
<p><strong>发送消息的方法，记得引入ElementUI</strong></p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//弹窗发送消息 以传入的参数而定</span></span><br><span class="line">    <span class="function"><span class="title">sendMessage</span>(<span class="params">messageContent, messageType</span>)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.$message(&#123;</span><br><span class="line">        <span class="attr">message</span>: messageContent,</span><br><span class="line">        <span class="attr">type</span>: messageType,</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;,</span><br></pre></td></tr></table></div></figure>

<p><strong>然后就是后台接收（如果是SSM项目，在SpringMVC配置文件中配置Bean</strong></p>
<p><strong>如果是SpringBoot项目，记得在application.properties中配置：</strong></p>
<p><mark> 见上方内容 </mark></p>
<p><strong>接下来，我们写后台的具体上传方法。</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//elementUI 上传方法</span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String UPLOAD_DIRECTORY = <span class="string">&quot;upload&quot;</span>;</span><br><span class="line">	</span><br><span class="line">    <span class="meta">@PostMapping(value = &quot;/uploading&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> TSMResult <span class="title">uploadFile</span><span class="params">(<span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file, HttpServletRequest request, TSMResult tsmResult)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (file.isEmpty()) &#123;</span><br><span class="line">            tsmResult.setData(<span class="number">0</span>);</span><br><span class="line">            tsmResult.setMessage(<span class="string">&quot;文件不可为空！&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> tsmResult;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 获取文件全名a.py</span></span><br><span class="line">        String fileName = file.getOriginalFilename();</span><br><span class="line">        <span class="comment">// 文件上传路径&lt;br&gt;        String templatePath = &quot;E:/file/template/&quot;</span></span><br><span class="line">        String templatePath = request.getServletContext().getRealPath(<span class="string">&quot;./&quot;</span>) + File.separator + UPLOAD_DIRECTORY;</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;文件路径：&quot;</span> + templatePath);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取文件的后缀名</span></span><br><span class="line">        String suffixName = fileName.substring(fileName.lastIndexOf(<span class="string">&quot;.&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">//获取文件名</span></span><br><span class="line">        String prefixName = fileName.substring(<span class="number">0</span>, fileName.lastIndexOf(<span class="string">&quot;.&quot;</span>));</span><br><span class="line">        <span class="comment">// 解决中文问题,liunx 下中文路径,图片显示问题</span></span><br><span class="line">        <span class="comment">//fileName = UUID.randomUUID() + suffixName;</span></span><br><span class="line">        File dest0 = <span class="keyword">new</span> File(templatePath);</span><br><span class="line">        <span class="comment">//prefixName + File.separator +</span></span><br><span class="line">        File dest = <span class="keyword">new</span> File(dest0, fileName);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">//文件上传-覆盖</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 检测是否存在目录</span></span><br><span class="line">            <span class="keyword">if</span> (!dest0.getParentFile().exists()) &#123;</span><br><span class="line">                dest0.getParentFile().mkdirs();</span><br><span class="line">                <span class="comment">//检测文件是否存在</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!dest.exists()) &#123;</span><br><span class="line">                dest.mkdirs();</span><br><span class="line">            &#125;</span><br><span class="line">            file.transferTo(dest);</span><br><span class="line"></span><br><span class="line">            <span class="comment">//上传成功后 将上传路径上传到数据库中</span></span><br><span class="line">            String filePathSaved = templatePath + File.separator;</span><br><span class="line">            teacherServer.saveFilePath(filePathSaved, fileName);</span><br><span class="line"></span><br><span class="line">            tsmResult.setData(<span class="number">1</span>);</span><br><span class="line">            tsmResult.setMessage(<span class="string">&quot;文件上传成功！&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> tsmResult;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            tsmResult.setData(<span class="number">0</span>);</span><br><span class="line">            tsmResult.setMessage(<span class="string">&quot;服务器错误，请稍后再试！&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> tsmResult;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></div></figure>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">teacherServer.saveFilePath(filePathSaved, fileName);</span><br></pre></td></tr></table></div></figure>

<p>这个代表，我们<strong>将这个上传的文件名字，以及对应的上传路径，写进数据库中</strong>。</p>
<p>对应服务层代码：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">saveFilePath</span><span class="params">(String filePathSaved, String fileName)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> sourceMapper.saveFilePath(filePathSaved, fileName);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></div></figure>

<p>对应mapper代码：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Insert(&quot;insert into source(source, papername) values (#&#123;filePath&#125;,#&#123;fileName&#125;)&quot;)</span></span><br><span class="line">   <span class="function"><span class="keyword">int</span> <span class="title">saveFilePath</span><span class="params">(<span class="meta">@Param(&quot;filePath&quot;)</span> String filePath, <span class="meta">@Param(&quot;fileName&quot;)</span> String fileName)</span></span>;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p>可以建立一个Source实体类，引入Lombok</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Integer id;</span><br><span class="line"><span class="keyword">private</span> String filePath;</span><br><span class="line"><span class="keyword">private</span> String fileName;</span><br></pre></td></tr></table></div></figure>

<p><strong>并且数据库也建立一个source表，其中字段名与这个Source实体类的属性名一模一样（避免Mybatis的字段映射ResultMap）</strong></p>

        <h1 id="实现文件下载"   >
          <a href="#实现文件下载" class="heading-link"><i class="fas fa-link"></i></a><a href="#实现文件下载" class="headerlink" title="实现文件下载"></a>实现文件下载</h1>
      <p><strong># 在实现文件的上传后，我们肯定会有相应的下载功能。</strong></p>
<p><em>即从上传目录中的文件中，去下载对应的文件。</em></p>
<ul>
<li><p>需求：我们将文件的信息以及路径，存进数据库了，也就代表：</p>
</li>
<li><p>我们“只能下载那些已经保存在数据库中的文件”</p>
</li>
</ul>

        <h2 id="JSP实现文件下载（且动态检测文件是否可下载）"   >
          <a href="#JSP实现文件下载（且动态检测文件是否可下载）" class="heading-link"><i class="fas fa-link"></i></a><a href="#JSP实现文件下载（且动态检测文件是否可下载）" class="headerlink" title="JSP实现文件下载（且动态检测文件是否可下载）"></a>JSP实现文件下载（且动态检测文件是否可下载）</h2>
      <ol>
<li>前端页面动态生成一个锚点（Bootstrap可加上按钮样式类）<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. 利用Ajax异步获取到分好页的论文（PageHelper插件）</span></span><br><span class="line"><span class="keyword">var</span> list = result.data.list</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 利用$.each来遍历这些数据 对每个数据进行筛选</span></span><br><span class="line">$.each(list, <span class="function"><span class="keyword">function</span> (<span class="params">index, item</span>) </span>&#123;	</span><br><span class="line">	<span class="comment">//3. 首先获取到即将下载的论文名(鉴于我们上传时 是将论文的文件名存进数据库的)</span></span><br><span class="line">	<span class="keyword">var</span> papername = item.papername  </span><br><span class="line">	</span><br><span class="line">	<span class="comment">//4. 为每一项“模拟按钮” 动态加上类 方便我们后期动态remove掉</span></span><br><span class="line">	<span class="keyword">var</span> download = $(<span class="string">&quot;&lt;a&gt;&lt;/a&gt;&quot;</span>).addClass(papername + <span class="string">&quot; btn btn-danger btn-sm&quot;</span>).append($(<span class="string">&quot;&lt;span&gt;&lt;/span&gt;&quot;</span>).addClass(<span class="string">&quot;glyphicon glyphicon-download&quot;</span>)).append(<span class="string">&quot;下载&quot;</span>).attr(<span class="string">&quot;href&quot;</span>, <span class="string">&quot;/DownloadServlet?paperName=&quot;</span> + item.papername);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></div></figure></li>
</ol>
<p><strong>注意到，我们这里的路径是：/DownloadServlet?paperName=xxx</strong></p>
<p>因此，我们肯定是以<code>get</code>的请求方式</p>
<ol start="2">
<li>后台controller层代码<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String UPLOAD_DIRECTORY = <span class="string">&quot;upload&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;/DownloadServlet&quot;)</span></span><br><span class="line">   <span class="keyword">public</span> ResponseEntity&lt;<span class="keyword">byte</span>[]&gt; fileDownload(</span><br><span class="line">           HttpServletRequest request,</span><br><span class="line">           <span class="meta">@RequestParam(&quot;paperName&quot;)</span> String fileName,</span><br><span class="line">           Model model) <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">       fileName = <span class="keyword">new</span> String(fileName.getBytes(<span class="string">&quot;ISO-8859-1&quot;</span>), <span class="string">&quot;UTF-8&quot;</span>); <span class="comment">//后台接受中文数据编码</span></span><br><span class="line">       fileName = fileName + <span class="string">&quot;.doc&quot;</span>;</span><br><span class="line"></span><br><span class="line">       String filePath = request.getServletContext().getRealPath(<span class="string">&quot;./&quot;</span>) + File.separator + UPLOAD_DIRECTORY + <span class="string">&quot;\\&quot;</span> + fileName;</span><br><span class="line">       File file = <span class="keyword">new</span> File(filePath);</span><br><span class="line">       HttpHeaders headers = <span class="keyword">new</span> HttpHeaders();</span><br><span class="line">       String downloadFile = <span class="keyword">new</span> String(fileName.getBytes(<span class="string">&quot;utf-8&quot;</span>), <span class="string">&quot;iso-8859-1&quot;</span>);</span><br><span class="line">       headers.setContentDispositionFormData(<span class="string">&quot;attachment&quot;</span>, downloadFile);</span><br><span class="line">       headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;<span class="keyword">byte</span>[]&gt;(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure></li>
</ol>
<p><strong>其实，上述代码是不够完整的，因为如果数据库中没有这个以.doc为后缀（后缀写死了）的文件，就会报错。</strong></p>
<p><strong>因此，我们需要在前端下载之前就进行一次查询：</strong></p>
<p><strong>如果该文件的文件名存到数据库里了，才给予下载（即才动态添加下载的锚点样式）</strong></p>
<ul>
<li>完整代码：写在$.each遍历中：<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 1. 利用Ajax异步获取到分好页的论文（PageHelper插件）</span></span><br><span class="line"><span class="keyword">var</span> list = result.data.list</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 利用$.each来遍历这些数据 对每个数据进行筛选</span></span><br><span class="line">$.each(list, <span class="function"><span class="keyword">function</span> (<span class="params">index, item</span>) </span>&#123;	</span><br><span class="line">	<span class="comment">//3. 首先获取到即将下载的论文名(鉴于我们上传时 是将论文的文件名存进数据库的)</span></span><br><span class="line">	<span class="keyword">var</span> papername = item.papername  </span><br><span class="line">	</span><br><span class="line">	<span class="comment">//4. 为每一项“模拟按钮” 动态加上类 方便我们后期动态remove掉</span></span><br><span class="line">	<span class="keyword">var</span> download = $(<span class="string">&quot;&lt;a&gt;&lt;/a&gt;&quot;</span>).addClass(papername + <span class="string">&quot; btn btn-danger btn-sm&quot;</span>).append($(<span class="string">&quot;&lt;span&gt;&lt;/span&gt;&quot;</span>).addClass(<span class="string">&quot;glyphicon glyphicon-download&quot;</span>)).append(<span class="string">&quot;下载&quot;</span>).attr(<span class="string">&quot;href&quot;</span>, <span class="string">&quot;/DownloadServlet?paperName=&quot;</span> + item.papername);</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//5. 查询该文件是否可下载</span></span><br><span class="line">	$.ajax(&#123;</span><br><span class="line">		<span class="attr">url</span>: <span class="string">&quot;isExistsFilename&quot;</span>,</span><br><span class="line">		<span class="attr">data</span>: &#123;<span class="string">&quot;paperName&quot;</span>: item.papername&#125;,</span><br><span class="line">		<span class="attr">type</span>: <span class="string">&quot;GET&quot;</span>,</span><br><span class="line">		<span class="attr">dataType</span>: <span class="string">&quot;JSON&quot;</span>,</span><br><span class="line">		<span class="attr">success</span>: <span class="function"><span class="keyword">function</span> (<span class="params">result</span>) </span>&#123;</span><br><span class="line">			<span class="comment">//数据库存储了文件信息的论文 才可以下载</span></span><br><span class="line">			<span class="comment">//如果为false表示不可下载 则根据对应的papername来remove样式</span></span><br><span class="line">			<span class="keyword">if</span>(result.data == <span class="literal">false</span>)&#123;</span><br><span class="line">				$(<span class="string">&quot;.&quot;</span> + item.papername).remove();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;,</span><br><span class="line">		<span class="attr">error</span>: <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">			<span class="built_in">console</span>.log(error)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></div></figure></li>
</ul>
<p><strong>查询的控制层代码：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(value = &quot;/isExistsFilename&quot;, method = RequestMethod.GET)</span></span><br><span class="line">   <span class="meta">@ResponseBody</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> TSMResult <span class="title">isExistsFilename</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">           <span class="meta">@RequestParam(&quot;paperName&quot;)</span> String paperName)</span> </span>&#123;</span><br><span class="line">       <span class="comment">//处理中文</span></span><br><span class="line">       Boolean isExists = <span class="keyword">false</span>;</span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">           paperName = <span class="keyword">new</span> String(paperName.getBytes(<span class="string">&quot;ISO-8859-1&quot;</span>), <span class="string">&quot;UTF-8&quot;</span>);</span><br><span class="line">           paperName = paperName + <span class="string">&quot;.doc&quot;</span>;</span><br><span class="line">           Source source = adminServer.isExistsPaperFile(paperName);</span><br><span class="line">           isExists = (source == <span class="keyword">null</span>) ? <span class="keyword">false</span> : <span class="keyword">true</span>;</span><br><span class="line">       &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">           System.out.println(<span class="string">&quot;检测到异常！&quot;</span>);</span><br><span class="line">           e.printStackTrace();</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">new</span> TSMResult(<span class="number">200</span>, <span class="string">&quot;查询成功&quot;</span>, isExists);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure>

<p>从代码中的三目运算符可以看出：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">isExists = (source == <span class="keyword">null</span>) ? <span class="keyword">false</span> : <span class="keyword">true</span>;</span><br></pre></td></tr></table></div></figure>

<ul>
<li><p>如果这个文件为空则会true，否则为false</p>
</li>
<li><p>也就是说，如果文件不为空，则为false，表示不可下载</p>
</li>
</ul>
<p><strong>服务层代码：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Source <span class="title">isExistsPaperFile</span><span class="params">(String paperName)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> sourceMapper.selectPaperFile(paperName);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>具体Source类看上方代码即可。</strong></p>
<p><strong>Mapper代码：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Select(&quot;select* from source where papername = #&#123;paperName&#125;&quot;)</span></span><br><span class="line"><span class="function">Source <span class="title">selectPaperFile</span><span class="params">(<span class="meta">@Param(&quot;paperName&quot;)</span> String paperName)</span></span>;</span><br></pre></td></tr></table></div></figure>


        <h1 id="实现通用JS代码全局引用"   >
          <a href="#实现通用JS代码全局引用" class="heading-link"><i class="fas fa-link"></i></a><a href="#实现通用JS代码全局引用" class="headerlink" title="实现通用JS代码全局引用"></a>实现通用JS代码全局引用</h1>
      
        <h2 id="ElementUI的Message消息提示、Notify通知等等"   >
          <a href="#ElementUI的Message消息提示、Notify通知等等" class="heading-link"><i class="fas fa-link"></i></a><a href="#ElementUI的Message消息提示、Notify通知等等" class="headerlink" title="ElementUI的Message消息提示、Notify通知等等"></a>ElementUI的Message消息提示、Notify通知等等</h2>
      <p><strong>我们希望在弹出消息或者通知（Notify）时</strong></p>
<ul>
<li>根据我们自定义的参数，来相应提示用户</li>
</ul>
<ol>
<li><p>提示用户更改信息成功</p>
</li>
<li><p>这个提示类型是success类型</p>
</li>
</ol>
<p>只需调用：</p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.$sendMessage(<span class="string">&#x27;这是消息内容&#x27;</span>, <span class="string">&#x27;info/success/error/warning&#x27;</span>)</span><br></pre></td></tr></table></div></figure>

<p><em>info 是灰色 success是绿色 error是红色 warning是黄色</em></p>

        <h3 id="创建通用功能的utils-js"   >
          <a href="#创建通用功能的utils-js" class="heading-link"><i class="fas fa-link"></i></a><a href="#创建通用功能的utils-js" class="headerlink" title="创建通用功能的utils.js"></a>创建通用功能的utils.js</h3>
      <ul>
<li>定义多个function 最后导出即可</li>
</ul>
<p><em>注意，这里有一个知识点：对于默认导出的函数，使用时函数名外不需要{xxx}</em></p>
<p><em>即直接： import XXX from ‘xxx/xxx’</em></p>
<p><strong>而如果有多个函数，想要按需引入的话，需要加上{}</strong></p>
<p>按需引入（包括默认导出函数）：</p>
<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; fun1, fun2 &#125; <span class="keyword">from</span> <span class="string">&#x27;xxx/xxx&#x27;</span></span><br></pre></td></tr></table></div></figure>

<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//弹窗发送消息 以传入的参数而定</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">sendMessage</span>(<span class="params">messageContent, messageType</span>) </span>&#123;</span><br><span class="line">	<span class="built_in">this</span>.$message(&#123;</span><br><span class="line">		<span class="attr">message</span>: messageContent,</span><br><span class="line">		<span class="attr">type</span>: messageType,</span><br><span class="line">	&#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">alertTest</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	alert(<span class="string">&#x27;这是测试方法！&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> sendMessage</span><br></pre></td></tr></table></div></figure>


        <h3 id="main-js中引入并使用"   >
          <a href="#main-js中引入并使用" class="heading-link"><i class="fas fa-link"></i></a><a href="#main-js中引入并使用" class="headerlink" title="main.js中引入并使用"></a>main.js中引入并使用</h3>
      <figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; sendMessage,loadingAnimation &#125; <span class="keyword">from</span> <span class="string">&#x27;./assets/js/utils&#x27;</span></span><br><span class="line">Vue.prototype.$sendMessage = sendMessage </span><br><span class="line">Vue.prototype.$alertTest = alertTest </span><br></pre></td></tr></table></div></figure>

<p>这样我们就可以，直接在vue项目中：使用<code>this.$sendMessage</code>来使用相应方法了。</p>

        <h1 id="HTML中引入VUE并使用ElementUI样式"   >
          <a href="#HTML中引入VUE并使用ElementUI样式" class="heading-link"><i class="fas fa-link"></i></a><a href="#HTML中引入VUE并使用ElementUI样式" class="headerlink" title="HTML中引入VUE并使用ElementUI样式"></a>HTML中引入VUE并使用ElementUI样式</h1>
      
        <h2 id="head标签引入ElementUI的CSS、JS以及VUE的JS"   >
          <a href="#head标签引入ElementUI的CSS、JS以及VUE的JS" class="heading-link"><i class="fas fa-link"></i></a><a href="#head标签引入ElementUI的CSS、JS以及VUE的JS" class="headerlink" title="head标签引入ElementUI的CSS、JS以及VUE的JS"></a>head标签引入ElementUI的CSS、JS以及VUE的JS</h2>
      <figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;https://unpkg.com/element-ui/lib/theme-chalk/index.css&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/vue/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/element-ui/lib/index.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="初始VUE（2-0版本）"   >
          <a href="#初始VUE（2-0版本）" class="heading-link"><i class="fas fa-link"></i></a><a href="#初始VUE（2-0版本）" class="headerlink" title="初始VUE（2.0版本）"></a>初始VUE（2.0版本）</h2>
      <ol>
<li>页面非body标签 标记</li>
</ol>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span> </span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></div></figure>
<ol start="2">
<li>vue挂载上去（可以<strong>使用template写HTML页面 如果已经有内容了就去掉template</strong>）<figure class="highlight js"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">      <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">      <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      	<span class="keyword">return</span> &#123;</span><br><span class="line">      			</span><br><span class="line">      	&#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">methods</span>: &#123;</span><br><span class="line">      	</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="function"><span class="title">created</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	  </span><br><span class="line">	  &#125;,</span><br><span class="line">	  <span class="function"><span class="title">mounted</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">			</span><br><span class="line">	  &#125;</span><br><span class="line">    &#125;)</span><br></pre></td></tr></table></div></figure></li>
</ol>
</div></div></article></section><nav class="paginator"><div class="paginator-inner"><span class="page-number current">1</span><a class="page-number" href="/blog/page/2/">2</a><span class="space">&hellip;</span><a class="page-number" href="/blog/page/5/">5</a><a class="extend next" rel="next" href="/blog/page/2/"><i class="fas fa-angle-right"></i></a></div></nav></div></div><div class="sidebar-wrap" id="sidebar-wrap"><aside class="sidebar" id="sidebar"><section class="sidebar-toc hide"></section><!-- ov = overview--><section class="sidebar-ov"><div class="sidebar-ov-author"><div class="sidebar-ov-author__avatar"><img class="sidebar-ov-author__avatar_img" src="/blog/images/avatar.jpg" alt="avatar"></div><p class="sidebar-ov-author__text">C'est la vie</p></div><div class="sidebar-ov-state"><a class="sidebar-ov-state-item sidebar-ov-state-item--posts" href="/blog/archives/"><div class="sidebar-ov-state-item__count">48</div><div class="sidebar-ov-state-item__name">归档</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--categories" href="/blog/categories/"><div class="sidebar-ov-state-item__count">19</div><div class="sidebar-ov-state-item__name">分类</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--tags" href="/blog/tags/"><div class="sidebar-ov-state-item__count">20</div><div class="sidebar-ov-state-item__name">标签</div></a></div><div class="sidebar-ov-cc"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" target="_blank" rel="noopener" data-popover="知识共享许可协议" data-popover-pos="up"><img src="/blog/images/cc-by-nc-sa.svg"></a></div></section></aside></div><div class="clearfix"></div></div></main><footer class="footer" id="footer"><div class="footer-inner"><div><span>Copyright © 2021</span><span class="footer__icon"><i class="fas fa-heart"></i></span><span>何水浪</span></div><div><span>由 <a href="http://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a> 强力驱动</span><span> v5.4.0</span><span class="footer__devider">|</span><span>主题 - <a href="https://github.com/liuyib/hexo-theme-stun/" title="Stun" target="_blank" rel="noopener">Stun</a></span><span> v2.6.2</span></div></div></footer><div class="loading-bar" id="loading-bar"><div class="loading-bar__progress"></div></div><div class="back2top" id="back2top"><span class="back2top__icon"><i class="fas fa-rocket"></i></span></div></div><div class="search-mask"></div><div class="search-popup"><span class="search-close"></span><div class="search-input"><input placeholder="搜索文章（支持多关键词，请用空格分隔）"></div><div class="search-results"></div></div><script src="https://cdn.jsdelivr.net/npm/jquery@v3.4.1/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.ui.min.js"></script><script>function initSearch() {
  var isXML = true;
  var search_path = 'search.json';

  if (!search_path) {
    search_path = 'search.xml';
  } else if (/json$/i.test(search_path)) {
    isXML = false;
  }

  var path = '/blog/' + search_path;
  $.ajax({
    url: path,
    dataType: isXML ? 'xml' : 'json',
    async: true,
    success: function (res) {
      var datas = isXML ? $('entry', res).map(function () {
        // 将 XML 转为 JSON
        return {
          title: $('title', this).text(),
          content: $('content', this).text(),
          url: $('url', this).text()
        };
      }).get() : res;
      var $input = $('.search-input input');
      var $result = $('.search-results');
      // 搜索对象（标题、内容）的权重，影响显示顺序
      var WEIGHT = { title: 100, content: 1 };
      var searchPost = function () {
        var searchText = $input.val().toLowerCase().trim();
        // 根据空白字符分隔关键字
        var keywords = searchText.split(/[\s]+/);
        // 搜索结果
        var matchPosts = [];

        // 有多个关键字时，将原文字整个保存下来
        if (keywords.length > 1) {
          keywords.push(searchText);
        }
        // 防止未输入字符时搜索
        if (searchText.length > 0) {
          datas.forEach(function (data) {
            var isMatch  = false;
            // 没有标题的文章使用预设的 i18n 变量代替
            var title = (data.title && data.title.trim()) || '[ 文章无标题 ]';
            var titleLower = title && title.toLowerCase();
            // 删除 HTML 标签 和 所有空白字符
            var content = data.content && data.content.replace(/<[^>]+>/g, '');
            var contentLower = content && content.toLowerCase();
            // 删除重复的 /
            var postURL = data.url && decodeURI(data.url).replace(/\/{2,}/g, '/');
            // 标题中匹配到的关键词
            var titleHitSlice = [];
            // 内容中匹配到的关键词
            var contentHitSlice = [];

            keywords.forEach(function (keyword) {
              /**
              * 获取匹配的关键词的索引
              * @param {String} keyword 要匹配的关键字
              * @param {String} text 原文字
              * @param {Boolean} caseSensitive 是否区分大小写
              * @param {Number} weight 匹配对象的权重。权重大的优先显示
              * @return {Array}
              */
              function getIndexByword (word, text, caseSensitive, weight) {
                if (!word || !text) {
                  return [];
                };

                var startIndex = 0; // 每次匹配的开始索引
                var index = -1;     // 匹配到的索引值
                var result = [];    // 匹配结果

                if (!caseSensitive) {
                  word = word.toLowerCase();
                  text = text.toLowerCase();
                }

                while((index = text.indexOf(word, startIndex)) !== -1) {
                  var hasMatch = false;
                  // 索引位置相同的关键词，保留长度较长的
                  titleHitSlice.forEach(function (hit) {
                    if (hit.index === index && hit.word.length < word.length) {
                      hit.word = word;
                      hasMatch = true;
                    }
                  });
                  startIndex = index + word.length;
                  !hasMatch && result.push({ index: index, word: word, weight: weight });
                }
                return result;
              }
              titleHitSlice = titleHitSlice.concat(getIndexByword(keyword, titleLower, false, WEIGHT.title));
              contentHitSlice = contentHitSlice.concat(getIndexByword(keyword, contentLower, false, WEIGHT.content));
            });

            var hitTitle = titleHitSlice.length;
            var hitContent = contentHitSlice.length;

            if (hitTitle > 0 || hitContent > 0) {
              isMatch = true;
            }
            if (isMatch) {
              ;[titleHitSlice, contentHitSlice].forEach(function (hit) {
                // 按照匹配文字的索引的递增顺序排序
                hit.sort(function (left, right) {
                  return left.index - right.index;
                });
              });
              /**
              * 给文本中匹配到的关键词添加标记，从而进行高亮显示
              * @param {String} text 原文本
              * @param {Array} hitSlice 匹配项的索引信息
              * @param {Number} start 开始索引
              * @param {Number} end 结束索引
              * @return {String}
              */
              function highlightKeyword (text, hitSlice, start, end) {
                if (!text || !hitSlice || !hitSlice.length) {
                  return;
                }

                var result = '';
                var startIndex = start;
                var endIndex = end;
                hitSlice.forEach(function (hit) {
                  if (hit.index < startIndex) {
                    return;
                  }

                  var hitWordEnd = hit.index + hit.word.length;
                  result += text.slice(startIndex, hit.index);
                  result += '<b>' + text.slice(hit.index, hitWordEnd) + '</b>';
                  startIndex = hitWordEnd;
                });
                result += text.slice(startIndex, endIndex);
                return result;
              }

              var postData = {};
              // 文章总的搜索权重
              var postWeight = titleHitSlice.length * WEIGHT.title + contentHitSlice.length * WEIGHT.content;
              // 标记匹配关键词后的标题
              var postTitle = highlightKeyword(title, titleHitSlice, 0, title.length) || title;
              // 标记匹配关键词后的内容
              var postContent;
              // 显示内容的长度
              var SHOW_WORD_LENGTH = 200;
              // 命中关键词前的字符显示长度
              var SHOW_WORD_FRONT_LENGTH = 20;
              var SHOW_WORD_END_LENGTH = SHOW_WORD_LENGTH - SHOW_WORD_FRONT_LENGTH;

              // 截取匹配的第一个字符，前后共 200 个字符来显示
              if (contentHitSlice.length > 0) {
                var firstIndex = contentHitSlice[0].index;
                var start = firstIndex > SHOW_WORD_FRONT_LENGTH ? firstIndex - SHOW_WORD_FRONT_LENGTH : 0;
                var end = firstIndex + SHOW_WORD_END_LENGTH;
                postContent = highlightKeyword(content, contentHitSlice, start, end);
              } else { // 未匹配到内容，直接截取前 200 个字符来显示
                postContent = content.slice(0, SHOW_WORD_LENGTH);
              }
              postData.title = postTitle;
              postData.content = postContent;
              postData.url = postURL;
              postData.weight = postWeight;
              matchPosts.push(postData);
            }
          });
        }

        var resultInnerHtml = '';
        if (matchPosts.length) {
          // 按权重递增的顺序排序，使权重大的优先显示
          matchPosts.sort(function (left, right) {
            return right.weight - left.weight;
          });
          resultInnerHtml += '<ul>';
          matchPosts.forEach(function (post) {
            resultInnerHtml += '<li><a class="search-results-title" href="' + post.url + '">';
            resultInnerHtml += post.title;
            resultInnerHtml += '</a><div class="search-results-content">';
            resultInnerHtml += post.content;
            resultInnerHtml += '</div></li>';
          });
          resultInnerHtml += '</ul>';
        } else {
          resultInnerHtml += '<div class="search-results-none"><i class="far fa-meh"></i></div>';
        }
        $result.html(resultInnerHtml);
      };
      $input.on('input', searchPost);
      $input.on('keyup', function (e) {
        if (e.keyCode === Stun.utils.codeToKeyCode('Enter')) {
          searchPost();
        }
      });
    }
  });
}

function closeSearch () {
  $('body').css({ overflow: 'auto' });
  $('.search-popup').css({ display: 'none' });
  $('.search-mask').css({ display: 'none' });
}

window.addEventListener('DOMContentLoaded', function () {
  Stun.utils.pjaxReloadLocalSearch = function () {
    $('.header-nav-search').on('click', function (e) {
      e.stopPropagation();
      $('body').css('overflow', 'hidden');
      $('.search-popup')
        .velocity('stop')
        .velocity('transition.expandIn', {
          duration: 300,
          complete: function () {
            $('.search-popup input').focus();
          }
        });
      $('.search-mask')
        .velocity('stop')
        .velocity('transition.fadeIn', {
          duration: 300
        });

      initSearch();
    });
    $('.search-mask, .search-close').on('click', function () {
      closeSearch();
    });
    $(document).on('keydown', function (e) {
      // Escape <=> 27
      if (e.keyCode === Stun.utils.codeToKeyCode('Escape')) {
        closeSearch();
      }
    });
  };

  Stun.utils.pjaxReloadLocalSearch();
}, false);

function safeOpenUrl(url) {
  var newTab = window.open();
  newTab.opener = null;
  newTab.location = url;
}

function extSearch(engine) {
  var engines = {
    google: 'https://www.google.com/search?q=',
    bing: 'https://cn.bing.com/search?q=',
    baidu: 'https://www.baidu.com/s?ie=UTF-8&wd=',
  };
  var host = window.location.host;
  var query = $('.search-input input').val().toLowerCase().trim();
  var uri = engines[engine] + query + ' site:' + host;

  if (query) {
    safeOpenUrl(uri);
  } else {
    Stun.utils.popAlert('warning', '请输入字符');
  }
}

var assistSearchList = window.CONFIG.assistSearch;

if (Array.isArray(assistSearchList)) {
  assistSearchList.forEach(function (name) {
    document.querySelector('.search-btns-item--' + name).addEventListener('click', function () {
      extSearch(name);
    }, false);
  });
}</script><script src="/blog/js/utils.js?v=2.6.2"></script><script src="/blog/js/stun-boot.js?v=2.6.2"></script><script src="/blog/js/scroll.js?v=2.6.2"></script><script src="/blog/js/header.js?v=2.6.2"></script><script src="/blog/js/sidebar.js?v=2.6.2"></script><script type="application/json" src="/blog/search.json"></script></body></html>